Rework how function types, type annotations, and typedefs are handled. (#1493)

In the process of trying to simplify the number of Piece classes, I noticed that FunctionPiece basically exists to split between the return type annotation and the rest of a function. That's pretty similar to how VariablePiece handles splitting between a variable's type annotation and name.

I unified those, but then it made typedefs format funny. Looking into
it, it's because typedefs have `=` but weren't using AssignPiece. Instead, they just never allowed splitting at the `=`. So I made that uniform with the rest of the style and used AssignPiece here.

That led to some weird looking code in cases like:

    Function(int someParameter) someVariable;

If that line doesn't fit, the formatter has to decide whether to split inside the type annotation or between the type and variable. There were different heuristics for return types followed by function names versus type annotations followed by variable names. Unifying those led to some weird output like:

    Function(
      int someParameter,
    ) Function(
      int someParameter,
    ) someVariable;

This is a variable whose type is a function that returns another function. Admittedly, no one writes code like this. Ultimately, I felt like the weirdness was from allowing the variable name to hang off the end of a split annotation. In most places in the style, if an inner construct splits, the outer one does too.

So I changed that. If a type annotation splits, then we also split after the type annotation too. That means after a return type before a function name, or after a variable type before a variable. So instead of allowing:

    SomeGenericClass<
      LongTypeArgument,
      AnotherLongTypeArgument
    > variable;

The split in the type argument list forces the variable name to split too:

    SomeGenericClass<
      LongTypeArgument,
      AnotherLongTypeArgument
    >
    variable;

I think I like how this looks a little more but I'm not sure. In practice, it doesn't matter much because it's rare for a type annotation to be long enough to split, but it does happen. For what it's worth, it's consistent with metadata on variables. If the metadata splits, we also split before the variable too:

    @SomeMetadata(
      'annotation argument',
      'another argument',
    )
    variable;

Thoughts?
diff --git a/lib/src/front_end/ast_node_visitor.dart b/lib/src/front_end/ast_node_visitor.dart
index 10644ba..678943a 100644
--- a/lib/src/front_end/ast_node_visitor.dart
+++ b/lib/src/front_end/ast_node_visitor.dart
@@ -223,6 +223,7 @@
 
   @override
   void visitBlockFunctionBody(BlockFunctionBody node) {
+    pieces.space();
     writeFunctionBodyModifiers(node);
     pieces.visit(node.block);
   }
@@ -430,7 +431,7 @@
       initializers = createCommaSeparated(node.initializers);
     }
 
-    var body = createFunctionBody(node.body);
+    var body = nodePiece(node.body);
 
     pieces.add(ConstructorPiece(header, parameters, body,
         canSplitParameters: node.parameters.parameters
@@ -595,6 +596,7 @@
   @override
   void visitExpressionFunctionBody(ExpressionFunctionBody node) {
     var operatorPiece = pieces.build(() {
+      pieces.space();
       writeFunctionBodyModifiers(node);
       pieces.token(node.functionDefinition);
     });
@@ -860,12 +862,7 @@
       pieces.token(node.name);
       pieces.visit(node.typeParameters);
       pieces.space();
-      pieces.token(node.equals);
-      // Don't bother allowing splitting after the `=`. It's always better to
-      // split inside the type parameter, type argument, or parameter lists of
-      // the typedef or the aliased type.
-      pieces.space();
-      pieces.visit(node.type);
+      pieces.add(AssignPiece(tokenPiece(node.equals), nodePiece(node.type)));
       pieces.token(node.semicolon);
     });
   }
@@ -1324,6 +1321,7 @@
 
   @override
   void visitNativeFunctionBody(NativeFunctionBody node) {
+    pieces.space();
     pieces.token(node.nativeKeyword);
     pieces.visit(node.stringLiteral, spaceBefore: true);
     pieces.token(node.semicolon);
@@ -1859,43 +1857,44 @@
 
   @override
   void visitVariableDeclarationList(VariableDeclarationList node) {
-    var header = pieces.build(
-        metadata: node.metadata,
+    pieces.withMetadata(node.metadata,
         // If the variable is part of a for loop, it looks weird to force the
         // metadata to split since it's in a sort of expression-ish location:
         //
         //     for (@meta var x in list) ...
         inlineMetadata: _parentContext == NodeContext.forLoopVariable, () {
-      pieces.modifier(node.lateKeyword);
-      pieces.modifier(node.keyword);
-      pieces.visit(node.type);
-    });
+      var header = pieces.build(() {
+        pieces.modifier(node.lateKeyword);
+        pieces.modifier(node.keyword);
+        pieces.visit(node.type);
+      });
 
-    var variables = <Piece>[];
-    for (var variable in node.variables) {
-      if ((variable.equals, variable.initializer)
-          case (var equals?, var initializer?)) {
-        var variablePiece = tokenPiece(variable.name);
+      var variables = <Piece>[];
+      for (var variable in node.variables) {
+        if ((variable.equals, variable.initializer)
+            case (var equals?, var initializer?)) {
+          var variablePiece = tokenPiece(variable.name);
 
-        var equalsPiece = pieces.build(() {
-          pieces.space();
-          pieces.token(equals);
-        });
+          var equalsPiece = pieces.build(() {
+            pieces.space();
+            pieces.token(equals);
+          });
 
-        var initializerPiece = nodePiece(initializer,
-            commaAfter: true, context: NodeContext.assignment);
+          var initializerPiece = nodePiece(initializer,
+              commaAfter: true, context: NodeContext.assignment);
 
-        variables.add(AssignPiece(
-            left: variablePiece,
-            equalsPiece,
-            initializerPiece,
-            canBlockSplitRight: initializer.canBlockSplit));
-      } else {
-        variables.add(tokenPiece(variable.name, commaAfter: true));
+          variables.add(AssignPiece(
+              left: variablePiece,
+              equalsPiece,
+              initializerPiece,
+              canBlockSplitRight: initializer.canBlockSplit));
+        } else {
+          variables.add(tokenPiece(variable.name, commaAfter: true));
+        }
       }
-    }
 
-    pieces.add(VariablePiece(header, variables, hasType: node.type != null));
+      pieces.add(VariablePiece(header, variables, hasType: node.type != null));
+    });
   }
 
   @override
diff --git a/lib/src/front_end/piece_factory.dart b/lib/src/front_end/piece_factory.dart
index f4bf814..0eaf751 100644
--- a/lib/src/front_end/piece_factory.dart
+++ b/lib/src/front_end/piece_factory.dart
@@ -10,7 +10,6 @@
 import '../piece/clause.dart';
 import '../piece/control_flow.dart';
 import '../piece/for.dart';
-import '../piece/function.dart';
 import '../piece/if_case.dart';
 import '../piece/infix.dart';
 import '../piece/list.dart';
@@ -570,49 +569,56 @@
       TypeParameterList? typeParameters,
       FormalParameterList? parameters,
       required FunctionBody body}) {
-    void writeModifiers() {
-      for (var keyword in modifiers) {
-        pieces.modifier(keyword);
-      }
-    }
-
     // Create a piece to attach metadata to the function.
     pieces.withMetadata(metadata, () {
-      Piece? returnTypePiece;
-      // Create a piece for the return type if there is one.
-      if (returnType != null) {
-        returnTypePiece = pieces.build(() {
-          writeModifiers();
-          pieces.visit(returnType);
-        });
-      }
-
-      var signature = pieces.build(() {
+      writeFunctionAndReturnType(modifiers, returnType, () {
         // If there's no return type, attach modifiers to the signature.
-        if (returnType == null) writeModifiers();
+        if (returnType == null) {
+          for (var keyword in modifiers) {
+            pieces.modifier(keyword);
+          }
+        }
 
         pieces.modifier(operatorKeyword);
         pieces.modifier(propertyKeyword);
         pieces.token(name);
         pieces.visit(typeParameters);
         pieces.visit(parameters);
+        pieces.visit(body);
       });
-
-      var bodyPiece = createFunctionBody(body);
-
-      pieces.add(FunctionPiece(returnTypePiece, signature,
-          isReturnTypeFunctionType: returnType is GenericFunctionType,
-          body: bodyPiece));
     });
   }
 
-  /// Creates a piece for a function, method, or constructor body.
-  Piece createFunctionBody(FunctionBody body) {
-    return pieces.build(() {
-      // Don't put a space before `;` bodies.
-      if (body is! EmptyFunctionBody) pieces.space();
-      pieces.visit(body);
+  /// Writes a return type followed by either a function signature (when writing
+  /// a function type annotation or function-typed formal) or a signature and a
+  /// body (when writing a function declaration).
+  ///
+  /// The [writeFunction] callback should write the function's signature and
+  /// body if there is one.
+  ///
+  /// If there is no return type, invokes [writeFunction] directly and returns.
+  /// Otherwise, writes the return type and function and wraps them in a piece
+  /// to allow splitting after the return type.
+  void writeFunctionAndReturnType(List<Token?> modifiers,
+      TypeAnnotation? returnType, void Function() writeFunction) {
+    if (returnType == null) {
+      writeFunction();
+      return;
+    }
+
+    var returnTypePiece = pieces.build(() {
+      for (var keyword in modifiers) {
+        pieces.modifier(keyword);
+      }
+
+      pieces.visit(returnType);
     });
+
+    var signature = pieces.build(() {
+      writeFunction();
+    });
+
+    pieces.add(VariablePiece(returnTypePiece, [signature], hasType: true));
   }
 
   /// If [parameter] has a [defaultValue] then writes a piece for the parameter
@@ -660,30 +666,9 @@
       {FormalParameter? parameter,
       Token? fieldKeyword,
       Token? period}) {
-    // If the type is a function-typed parameter with a default value, then
-    // grab the default value from the parent node.
-    (Token separator, Expression value)? defaultValueRecord;
-    if (parameter?.parent
-        case DefaultFormalParameter(:var separator?, :var defaultValue?)) {
-      defaultValueRecord = (separator, defaultValue);
-    }
-
     var metadata = parameter?.metadata ?? const <Annotation>[];
     pieces.withMetadata(metadata, inlineMetadata: true, () {
-      Piece? returnTypePiece;
-      if (returnType != null) {
-        returnTypePiece = pieces.build(() {
-          // Attach any parameter modifiers to the return type.
-          if (parameter != null) {
-            pieces.modifier(parameter.requiredKeyword);
-            pieces.modifier(parameter.covariantKeyword);
-          }
-
-          pieces.visit(returnType);
-        });
-      }
-
-      var signature = pieces.build(() {
+      void write() {
         // If there's no return type, attach the parameter modifiers to the
         // signature.
         if (parameter != null && returnType == null) {
@@ -697,10 +682,11 @@
         pieces.visit(typeParameters);
         pieces.visit(parameters);
         pieces.token(question);
-      });
+      }
 
-      var function = FunctionPiece(returnTypePiece, signature,
-          isReturnTypeFunctionType: returnType is GenericFunctionType);
+      var returnTypeModifiers = parameter != null
+          ? [parameter.requiredKeyword, parameter.covariantKeyword]
+          : const <Token?>[];
 
       // TODO(rnystrom): It would be good if the AssignPiece created for the
       // default value could treat the parameter list on the left-hand side as
@@ -710,7 +696,19 @@
       // practice, it doesn't really matter since function-typed formals are
       // deprecated, default values on function-typed parameters are rare, and
       // when both occur, they rarely split.
-      writeDefaultValue(function, defaultValueRecord);
+      // If the type is a function-typed parameter with a default value, then
+      // grab the default value from the parent node and attach it to the
+      // function.
+      if (parameter?.parent
+          case DefaultFormalParameter(:var separator?, :var defaultValue?)) {
+        var function = pieces.build(() {
+          writeFunctionAndReturnType(returnTypeModifiers, returnType, write);
+        });
+
+        writeDefaultValue(function, (separator, defaultValue));
+      } else {
+        writeFunctionAndReturnType(returnTypeModifiers, returnType, write);
+      }
     });
   }
 
diff --git a/lib/src/piece/function.dart b/lib/src/piece/function.dart
deleted file mode 100644
index df3730b..0000000
--- a/lib/src/piece/function.dart
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-import '../back_end/code_writer.dart';
-import 'piece.dart';
-
-/// Piece for a function declaration, function type, or function-typed
-/// parameter.
-///
-/// Handles splitting between the return type and the rest of the function.
-class FunctionPiece extends Piece {
-  /// The return type annotation, if any.
-  final Piece? _returnType;
-
-  /// The rest of the function type signature: name, type parameters,
-  /// parameters, etc.
-  final Piece _signature;
-
-  /// If this is a function declaration with a (non-empty `;`) body, the body.
-  final Piece? _body;
-
-  /// Whether the return type is a function type.
-  ///
-  /// When it is, allow splitting fairly cheaply because the return type is
-  /// usually pretty big and looks good on its own line, or at least better
-  /// then splitting inside the return type's parameter list. Prefers:
-  ///
-  ///     Function(int x, int y)
-  ///     returnFunction() { ... }
-  ///
-  /// Over:
-  ///
-  ///     Function(
-  ///       int x,
-  ///       int y,
-  ///     ) returnFunction() { ... }
-  ///
-  /// If the return type is *not* a function type, is almost always looks worse
-  /// to split at the return type, so make that high cost.
-  final bool _isReturnTypeFunctionType;
-
-  FunctionPiece(this._returnType, this._signature,
-      {required bool isReturnTypeFunctionType, Piece? body})
-      : _body = body,
-        _isReturnTypeFunctionType = isReturnTypeFunctionType;
-
-  @override
-  List<State> get additionalStates => [if (_returnType != null) State.split];
-
-  @override
-  int stateCost(State state) {
-    if (state == State.split) return _isReturnTypeFunctionType ? 1 : 4;
-    return super.stateCost(state);
-  }
-
-  @override
-  void format(CodeWriter writer, State state) {
-    if (_returnType case var returnType?) {
-      // A split inside the return type forces splitting after the return type.
-      writer.format(returnType, allowNewlines: state == State.split);
-
-      // A split in the type parameters or parameters does not force splitting
-      // after the return type.
-      writer.splitIf(state == State.split);
-    }
-
-    writer.format(_signature);
-
-    if (_body case var body?) writer.format(body);
-  }
-
-  @override
-  void forEachChild(void Function(Piece piece) callback) {
-    if (_returnType case var returnType?) callback(returnType);
-    callback(_signature);
-    if (_body case var body?) callback(body);
-  }
-
-  @override
-  String get debugName => 'Fn';
-}
diff --git a/lib/src/piece/variable.dart b/lib/src/piece/variable.dart
index b90b3fa..90738ec 100644
--- a/lib/src/piece/variable.dart
+++ b/lib/src/piece/variable.dart
@@ -8,7 +8,8 @@
 /// A variable declaration.
 ///
 /// Used for local variable declaration statements, top-level variable
-/// declarations and field declarations.
+/// declarations and field declarations. Also used to handle splitting between
+/// a function or function type's return type and the rest of the function.
 ///
 /// Typed and untyped variables have slightly different splitting logic.
 /// Untyped variables never split after the keyword but do indent subsequent
@@ -60,7 +61,7 @@
 
   @override
   void format(CodeWriter writer, State state) {
-    writer.format(_header);
+    writer.format(_header, allowNewlines: state != State.unsplit);
 
     // If we split at the variables (but not the type), then indent the
     // variables and their initializers.
diff --git a/test/tall/declaration/typedef.unit b/test/tall/declaration/typedef.unit
index d34e8ea..093fd11 100644
--- a/test/tall/declaration/typedef.unit
+++ b/test/tall/declaration/typedef.unit
@@ -10,22 +10,25 @@
 >>> Split in function type parameter list.
 typedef   SomeFunc=ReturnType  Function(int param,   double other);
 <<<
-typedef SomeFunc = ReturnType Function(
-  int param,
-  double other,
-);
+typedef SomeFunc =
+    ReturnType Function(
+      int param,
+      double other,
+    );
 >>> Nested function type.
 typedef SomeFunc = Function(int first, Function(int first, bool second, String third) second, String third);
 <<<
-typedef SomeFunc = Function(
-  int first,
-  Function(
-    int first,
-    bool second,
-    String third,
-  ) second,
-  String third,
-);
+typedef SomeFunc =
+    Function(
+      int first,
+      Function(
+        int first,
+        bool second,
+        String third,
+      )
+      second,
+      String third,
+    );
 >>> Generic typedef.
 typedef  Foo  <  A  ,  B  >  =  Function  (  A  a  ,  B  b  )  ;
 <<<
@@ -41,23 +44,25 @@
 >>> Split function type parameters.
 typedef G = T Function<TypeOne, TypeTwo, TypeThree>();
 <<<
-typedef G = T Function<
-  TypeOne,
-  TypeTwo,
-  TypeThree
->();
+typedef G =
+    T Function<
+      TypeOne,
+      TypeTwo,
+      TypeThree
+    >();
 >>> Split function type and value parameters.
 typedef G = T Function<TypeOne, TypeTwo, TypeThree>(TypeOne one, TypeTwo two, TypeThree three);
 <<<
-typedef G = T Function<
-  TypeOne,
-  TypeTwo,
-  TypeThree
->(
-  TypeOne one,
-  TypeTwo two,
-  TypeThree three,
-);
+typedef G =
+    T Function<
+      TypeOne,
+      TypeTwo,
+      TypeThree
+    >(
+      TypeOne one,
+      TypeTwo two,
+      TypeThree three,
+    );
 >>> Split typedef type parameters and function parameters.
 typedef LongfunctionType<First, Second, Third, Fourth, Fifth, Sixth> = Function<Seventh>(First first, Second second, Third third, Fourth fourth);
 <<<
@@ -68,12 +73,13 @@
   Fourth,
   Fifth,
   Sixth
-> = Function<Seventh>(
-  First first,
-  Second second,
-  Third third,
-  Fourth fourth,
-);
+> =
+    Function<Seventh>(
+      First first,
+      Second second,
+      Third third,
+      Fourth fourth,
+    );
 >>> Split typedef type parameters.
 typedef LongfunctionType<First, Second, Third, Fourth, Fifth, Sixth> = Type;
 <<<
@@ -95,28 +101,30 @@
   Fourth,
   Fifth,
   Sixth
-> = Function<
-  Seventh,
-  Eighth,
-  Ninth,
-  Tenth,
-  Eleventh,
-  Twelfth,
-  Thirteenth
->(
-  First first,
-  Second second,
-  Third third,
-  Fourth fourth,
-);
+> =
+    Function<
+      Seventh,
+      Eighth,
+      Ninth,
+      Tenth,
+      Eleventh,
+      Twelfth,
+      Thirteenth
+    >(
+      First first,
+      Second second,
+      Third third,
+      Fourth fourth,
+    );
 >>> Split in non-function type argument list.
 typedef G = SomeType<TypeOne, TypeTwo, TypeThree>;
 <<<
-typedef G = SomeType<
-  TypeOne,
-  TypeTwo,
-  TypeThree
->;
+typedef G =
+    SomeType<
+      TypeOne,
+      TypeTwo,
+      TypeThree
+    >;
 >>> Split typedef type parameters and non-function type arguments.
 typedef LongGenericType<First, Second, Third, Fourth, Fifth, Sixth> = AnotherType<First, Second, Third, Fourth>;
 <<<
@@ -127,21 +135,26 @@
   Fourth,
   Fifth,
   Sixth
-> = AnotherType<
-  First,
-  Second,
-  Third,
-  Fourth
->;
+> =
+    AnotherType<
+      First,
+      Second,
+      Third,
+      Fourth
+    >;
 >>> Prefer splitting parameter list over type parameter list.
-typedef Generic = R Function<T, R>(T param);
+typedef Generic = R Function<T, R, S, U>(T param, R another);
 <<<
-typedef Generic = R Function<T, R>(
-  T param,
-);
+typedef Generic =
+    R Function<T, R, S, U>(
+      T param,
+      R another,
+    );
 >>>
-typedef Generic<T, R> = R Function(T param);
+typedef Generic<T, R> = R Function<T, R, S, U>(T param, R another);
 <<<
-typedef Generic<T, R> = R Function(
-  T param,
-);
\ No newline at end of file
+typedef Generic<T, R> =
+    R Function<T, R, S, U>(
+      T param,
+      R another,
+    );
\ No newline at end of file
diff --git a/test/tall/declaration/typedef_comment.unit b/test/tall/declaration/typedef_comment.unit
index a930208..e210507 100644
--- a/test/tall/declaration/typedef_comment.unit
+++ b/test/tall/declaration/typedef_comment.unit
@@ -16,13 +16,14 @@
 Type;
 <<<
 typedef Alias = // c
-Type;
+    Type;
 >>> Line comment after type.
 typedef Alias = Type // c
 ;
 <<<
-typedef Alias = Type // c
-;
+typedef Alias =
+    Type // c
+    ;
 >>> Line comment after `;`.
 typedef Alias = Type; // c
 <<<
diff --git a/test/tall/expression/collection_for.stmt b/test/tall/expression/collection_for.stmt
index 494ea6b..d62528a 100644
--- a/test/tall/expression/collection_for.stmt
+++ b/test/tall/expression/collection_for.stmt
@@ -56,7 +56,8 @@
     LongGenericTypeName<
       TypeArg,
       AnotherTypeArgument
-    > a = 0;
+    >
+    a = 0;
     a < 1;
     a++
   )
@@ -70,7 +71,8 @@
     LongGenericTypeName<
       TypeArg,
       AnotherTypeArgument
-    > a;
+    >
+    a;
     ;
   )
     body,
diff --git a/test/tall/pattern/declared_variable_comment.stmt b/test/tall/pattern/declared_variable_comment.stmt
index bb039c0..37124f4 100644
--- a/test/tall/pattern/declared_variable_comment.stmt
+++ b/test/tall/pattern/declared_variable_comment.stmt
@@ -12,9 +12,8 @@
 if (obj case var // c
 x) {;}
 <<<
-if (obj
-    case var // c
-        x) {
+if (obj case var // c
+    x) {
   ;
 }
 >>> Line comment after variable (looks weird, but user should move comment).
@@ -42,8 +41,7 @@
   ;
 }
 <<<
-if (obj
-    case final // c
-        thisIsReallyQuiteAVeryLongVariableName) {
+if (obj case final // c
+    thisIsReallyQuiteAVeryLongVariableName) {
   ;
 }
\ No newline at end of file
diff --git a/test/tall/regression/1200/1212.unit b/test/tall/regression/1200/1212.unit
index 11c4d26..38696e3 100644
--- a/test/tall/regression/1200/1212.unit
+++ b/test/tall/regression/1200/1212.unit
@@ -18,179 +18,186 @@
     required TResult Function() initialize,
     required TResult Function(AppState state) receiveUpdatedAppState,
     required TResult Function() completedInitialFlow,
-    required TResult Function(
-      RouteId<CommonPageRoutePaywall> routeId,
-    ) dismissPaywall,
-    required TResult Function(
-      NotificationPermission status,
-    ) receiveNotificationPermissionStatus,
+    required TResult Function(RouteId<CommonPageRoutePaywall> routeId)
+    dismissPaywall,
+    required TResult Function(NotificationPermission status)
+    receiveNotificationPermissionStatus,
     required TResult Function(Object error, StackTrace stackTrace) receiveError,
-    required TResult Function(
-      Object error,
-      StackTrace stackTrace,
-    ) receiveNonFatalError,
-    required TResult Function(
-      Object error,
-      StackTrace stackTrace,
-    ) receiveProjectOperationError,
+    required TResult Function(Object error, StackTrace stackTrace)
+    receiveNonFatalError,
+    required TResult Function(Object error, StackTrace stackTrace)
+    receiveProjectOperationError,
     required TResult Function(String? error) showErrorDialog,
     required TResult Function(bool success) handleNetworkOperationResult,
     required TResult Function(MineralProject project) openProject,
     required TResult Function(
       LegacyProject legacyProject,
       MineralProject mineralProject,
-    ) migratedProject,
+    )
+    migratedProject,
     required TResult Function(
       String collectionId,
       Template template,
       bool asContentCreator,
-    ) openTemplate,
+    )
+    openTemplate,
     required TResult Function(EditorSize size) openEditorWithSize,
     required TResult Function() openEditorAndCreateNewProject,
-    required TResult Function(
-      Uri uri,
-      bool openedAppThroughUri,
-    ) receivedDynamicLink,
+    required TResult Function(Uri uri, bool openedAppThroughUri)
+    receivedDynamicLink,
     required TResult Function(NavigationAction<AppRoute> action) mainNavigation,
-    required TResult Function(
-      RouteId<HomeRoute> routeId,
-      HomeAction action,
-    ) home,
-    required TResult Function(
-      RouteId<SplashRoute> routeId,
-      SplashAction action,
-    ) splash,
+    required TResult Function(RouteId<HomeRoute> routeId, HomeAction action)
+    home,
+    required TResult Function(RouteId<SplashRoute> routeId, SplashAction action)
+    splash,
     required TResult Function(
       RouteId<SurveyRoute> routeId,
       MagmaSurveyAction action,
-    ) survey,
+    )
+    survey,
     required TResult Function(RouteId<AckRoute> routeId, AckAction action) ack,
     required TResult Function(
       RouteId<SubInfoRoute> routeId,
       MagmaSubInfoAction action,
-    ) subInfo,
+    )
+    subInfo,
     required TResult Function(
       RouteId<ProjectOptionsRoute> routeId,
       ProjectOptionsAction action,
-    ) projectOptions,
+    )
+    projectOptions,
     required TResult Function(InitializationAction action) initialization,
     required TResult Function(ContentAction action) content,
     required TResult Function(
       RouteId<ErrorDialogRoute> routeId,
       ErrorDialogAction action,
-    ) errorDialog,
+    )
+    errorDialog,
     required TResult Function(
       RouteId<InfoDialogRoute> routeId,
       InfoDialogAction action,
-    ) infoDialog,
-    required TResult Function(
-      MagmaRatingConfiguration configuration,
-    ) dismissedRating,
+    )
+    infoDialog,
+    required TResult Function(MagmaRatingConfiguration configuration)
+    dismissedRating,
     required TResult Function(
       RouteId<SupportRoute> routeId,
       MagmaSupportAction action,
-    ) support,
+    )
+    support,
     required TResult Function(
       RouteId<ClayEditorRoute> routeId,
       EditorRootAction action,
-    ) clayEditor,
+    )
+    clayEditor,
     required TResult Function(
       RouteId<TemplateSurveyRoute> routeId,
       MagmaTemplateSurveyAction action,
-    ) templateSurvey,
+    )
+    templateSurvey,
     required TResult Function(
       RouteId<CollabRoute> routeId,
       MagmaCollabAction action,
-    ) collab,
+    )
+    collab,
     required TResult Function(
       RouteId<RedeemCodeRoute> routeId,
       MagmaRedeemCodeAction action,
-    ) redeemCode,
+    )
+    redeemCode,
     required TResult Function(
       RouteId<OutdatedDialogRoute> routeId,
       OutdatedDialogAction action,
-    ) outdatedDialog,
+    )
+    outdatedDialog,
     required TResult Function(MagazineAction action) magazine,
     required TResult Function(
       RouteId<TemplateCollectionListRoute> routeId,
       TemplateCollectionListAction action,
-    ) templateCollectionList,
+    )
+    templateCollectionList,
     required TResult Function(
       RouteId<CollectionDetailRoute> routeId,
       CollectionDetailAction action,
-    ) collectionDetail,
+    )
+    collectionDetail,
     required TResult Function(
       RouteId<SimpleNewProjectRoute> routeId,
       SimpleNewProjectAction action,
-    ) simpleNewProject,
+    )
+    simpleNewProject,
     required TResult Function(
       RouteId<AppOnboardingFlowRoute> routeId,
       OnboardingFlowAction action,
-    ) onboardingFlow,
+    )
+    onboardingFlow,
     required TResult Function(String locale) receiveUserLocale,
     required TResult Function(AuthenticationAction action) authentication,
-    required TResult Function(
-      ToastType type,
-      Duration? autoDismissAfter,
-    ) showToast,
+    required TResult Function(ToastType type, Duration? autoDismissAfter)
+    showToast,
     required TResult Function() hideToast,
     required TResult Function() dispose,
     required TResult Function(LoginRouteState routeState) pushLogin,
     required TResult Function(
       RouteId<UpdateEmailRoute> routeId,
       UpdateEmailAction action,
-    ) updateEmail,
+    )
+    updateEmail,
     required TResult Function(
       RouteId<AppDeleteAccountRoute> routeId,
       DeleteAccountAction action,
-    ) deleteAccount,
+    )
+    deleteAccount,
     required TResult Function(
       RouteId<AppMultipleSubscriptionsRoute> routeId,
       MultipleSubscriptionsAction action,
-    ) multipleSubscriptions,
+    )
+    multipleSubscriptions,
     required TResult Function(
       RouteId<AppExpiredLinkRoute> routeId,
       MagmaExpiredLinkAction action,
-    ) expiredLink,
+    )
+    expiredLink,
     required TResult Function(CommonPageAction action) common,
     required TResult Function() fetchFcmToken,
     required TResult Function(String? token) receivedFcmToken,
     required TResult Function(
       RouteId<AppUnlockRoute> routeId,
       UnlockAction action,
-    ) unlock,
+    )
+    unlock,
     required TResult Function() setShouldSyncPaymentsAfterFirstStartup,
-    required TResult Function(
-      CustomerPurchaseResult result,
-    ) handleCustomerPurchaseResult,
+    required TResult Function(CustomerPurchaseResult result)
+    handleCustomerPurchaseResult,
     required TResult Function() handleIntent,
     required TResult Function(
       RouteId<AppPaymentIssuesRoute> routeId,
       PaymentIssuesAction action,
-    ) paymentIssues,
+    )
+    paymentIssues,
     required TResult Function(
       RouteId<AppSubscriptionCancellationFlowRoute> routeId,
       SubscriptionCancellationFlowAction action,
-    ) subscriptionCancellationFlow,
-    required TResult Function(
-      BuiltList<FirebaseProject> remoteProjects,
-    ) receivedRemoteProjects,
+    )
+    subscriptionCancellationFlow,
+    required TResult Function(BuiltList<FirebaseProject> remoteProjects)
+    receivedRemoteProjects,
     required TResult Function() uploadRemoteProject,
     required TResult Function(bool shouldRestore) abortUpload,
     required TResult Function(bool background) setBackgroundState,
     required TResult Function(
       RouteId<AppPaymentMethodSettingsRoute> routeId,
       PaymentMethodSettingsAction action,
-    ) paymentMethodSettings,
+    )
+    paymentMethodSettings,
     required TResult Function(String id) showSurvey,
-    required TResult Function(
-      String id,
-      Iterable<String> templateIds,
-    ) showTemplateSurvey,
+    required TResult Function(String id, Iterable<String> templateIds)
+    showTemplateSurvey,
     required TResult Function(
       RouteId<AppRouteSubscriptionAlreadyAssigned> routeId,
       SubscriptionAlreadyAssignedAction action,
-    ) subscriptionAlreadyAssigned,
+    )
+    subscriptionAlreadyAssigned,
   }) {
     return projectOptions(routeId, action);
   }
diff --git a/test/tall/type/function.stmt b/test/tall/type/function.stmt
index f4ae4f5..49d22b0 100644
--- a/test/tall/type/function.stmt
+++ b/test/tall/type/function.stmt
@@ -37,14 +37,16 @@
 Function<T, R>(
   longParameterName,
   anotherLongParameter,
-) f;
+)
+f;
 >>> Split type parameters.
 Function<LongTypeName, AnotherLongTypeName>(parameter) f;
 <<<
 Function<
   LongTypeName,
   AnotherLongTypeName
->(parameter) f;
+>(parameter)
+f;
 >>> Split type parameters and value parameters.
 Function<LongTypeName, AnotherLongTypeName>(longParameterName, anotherLongParameter) f;
 <<<
@@ -54,7 +56,8 @@
 >(
   longParameterName,
   anotherLongParameter,
-) f;
+)
+f;
 >>> Nullable types.
 int  ?  Function  (  int  ?  i  , {  String  ?  s  }  )  ?  f;
 <<<
@@ -67,7 +70,8 @@
   second,
   third,
   fourth,
-) f;
+)
+f;
 >>> Split parameters all optional.
 void Function([first, second, third, fourth]) f;
 <<<
@@ -76,7 +80,8 @@
   second,
   third,
   fourth,
-]) f;
+])
+f;
 >>> Split parameters all named.
 void Function({bool first, double second, int third}) f;
 <<<
@@ -84,7 +89,8 @@
   bool first,
   double second,
   int third,
-}) f;
+})
+f;
 >>> Split parameters with optional.
 void Function(first, second, [third, fourth]) f;
 <<<
@@ -93,7 +99,8 @@
   second, [
   third,
   fourth,
-]) f;
+])
+f;
 >>> Split parameters with named.
 void Function(first, second, {bool third, double fourth}) f;
 <<<
@@ -102,7 +109,8 @@
   second, {
   bool third,
   double fourth,
-}) f;
+})
+f;
 >>> Remove trailing comma from mandatory if unsplit.
 Function(
   first,
@@ -132,7 +140,8 @@
 Function(
   parameter1,
   void printFn(param1, param2),
-) f;
+)
+f;
 >>> Split function typed parameter.
 Function(int callback(parameter1, parameter2, parameter3, parameter4)) f;
 <<<
@@ -143,7 +152,8 @@
     parameter3,
     parameter4,
   ),
-) f;
+)
+f;
 >>> Required function typed formal.
 Function  (  {  required  void  callback  (  )  }  )  f  ;
 <<<
@@ -154,7 +164,8 @@
 Function(
   VerylongParameterType
   longParameterName,
-) f;
+)
+f;
 >>> Split in parameter type does not split before parameter.
 Function(Generic<LongTypeArgument, AnotherLongTypeName> parameter) f;
 <<<
@@ -162,8 +173,10 @@
   Generic<
     LongTypeArgument,
     AnotherLongTypeName
-  > parameter,
-) f;
+  >
+  parameter,
+)
+f;
 >>> Split in nested function type forces outer split.
 Function(int, String, Function(parameter1, parameter2, parameter3)) f;
 <<<
@@ -175,7 +188,8 @@
     parameter2,
     parameter3,
   ),
-) f;
+)
+f;
 >>> Split in type arguments.
 Function<Parameter1, Parameter2, Parameter3>() f;
 <<<
@@ -183,19 +197,22 @@
   Parameter1,
   Parameter2,
   Parameter3
->() f;
+>()
+f;
 >>> Split after return type.
 GenericClass<Parameter1, Parameter2> Function() f;
 <<<
 GenericClass<Parameter1, Parameter2>
-Function() f;
+Function()
+f;
 >>> Chained return types.
 Function<Argument>(String) Function<Argument>(num) Function<Argument>(int) Function<Argument>(bool) longVariable;
 <<<
 Function<Argument>(String)
 Function<Argument>(num)
 Function<Argument>(int)
-Function<Argument>(bool) longVariable;
+Function<Argument>(bool)
+longVariable;
 >>> Split before `required`.
 longMethod({required parameterNameHere}) {}
 <<<
@@ -227,12 +244,13 @@
   ;
 }
 >>> Split single long positional record type field.
-function((VeryLongTypeName___________________,) param) {;}
+function((VeryLongTypeName________________,) /* comment */ param) {;}
 <<<
 function(
   (
-    VeryLongTypeName___________________,
-  ) param,
+    VeryLongTypeName________________,
+  ) /* comment */
+  param,
 ) {
   ;
 }
@@ -246,7 +264,8 @@
     TypeName,
     TypeName,
     TypeName,
-  ) record,
+  )
+  record,
 ) {
   ;
 }
diff --git a/test/tall/type/function_comment.stmt b/test/tall/type/function_comment.stmt
index a0aa680..3236224 100644
--- a/test/tall/type/function_comment.stmt
+++ b/test/tall/type/function_comment.stmt
@@ -52,7 +52,8 @@
   /* c */
   a,
   b,
-) x;
+)
+x;
 >>> Non-inline block comment before ",".
 Function(a
 /* c */
@@ -62,7 +63,8 @@
   a,
   /* c */
   b,
-) x;
+)
+x;
 >>> Non-inline block comment after ",".
 Function(a,
 /* c */
@@ -72,7 +74,8 @@
   a,
   /* c */
   b,
-) x;
+)
+x;
 >>> Non-inline block comment before "[".
 Function(a
 /* c */
@@ -82,7 +85,8 @@
   a, [
   /* c */
   b,
-]) x;
+])
+x;
 >>> Non-inline block comment after "[".
 Function([
 /* c */
@@ -91,7 +95,8 @@
 Function([
   /* c */
   arg,
-]) x;
+])
+x;
 >>> Non-inline block comment before "]".
 Function([arg
 /* c */
@@ -100,7 +105,8 @@
 Function([
   arg,
   /* c */
-]) x;
+])
+x;
 >>> Non-inline block comment after "]".
 Function([arg]
 /* c */
@@ -109,7 +115,8 @@
 Function([
   arg,
   /* c */
-]) x;
+])
+x;
 >>> Non-inline block comment before "{".
 Function(a,
 /* c */
@@ -119,7 +126,8 @@
   a, {
   /* c */
   int b,
-}) x;
+})
+x;
 >>> Non-inline block comment after "{".
 Function({
 /* c */
@@ -128,7 +136,8 @@
 Function({
   /* c */
   int arg,
-}) x;
+})
+x;
 >>> Non-inline block comment before "}".
 Function({int arg
 /* c */
@@ -137,7 +146,8 @@
 Function({
   int arg,
   /* c */
-}) x;
+})
+x;
 >>> Non-inline block comment after "{".
 Function({int arg}
 /* c */
@@ -146,7 +156,8 @@
 Function({
   int arg,
   /* c */
-}) x;
+})
+x;
 >>> Line comment before first parameter.
 Function(// c
 a,b) x;
@@ -155,7 +166,8 @@
   // c
   a,
   b,
-) x;
+)
+x;
 >>> Line comment before ",".
 Function(a// c
 ,b) x;
@@ -163,7 +175,8 @@
 Function(
   a, // c
   b,
-) x;
+)
+x;
 >>> Line comment after ",".
 Function(a,// c
 b) x;
@@ -171,7 +184,8 @@
 Function(
   a, // c
   b,
-) x;
+)
+x;
 >>> Line comment before "[".
 Function(a,// c
 [b]) x;
@@ -180,7 +194,8 @@
 Function(
   a, [ // c
   b,
-]) x;
+])
+x;
 >>> Line comment after "[".
 Function([// c
 arg]) x;
@@ -188,21 +203,24 @@
 Function([
   // c
   arg,
-]) x;
+])
+x;
 >>> Line comment before "]".
 Function([arg// c
 ]) x;
 <<<
 Function([
   arg, // c
-]) x;
+])
+x;
 >>> Line comment after "]".
 Function([arg]// c
 ) x;
 <<<
 Function([
   arg, // c
-]) x;
+])
+x;
 >>> Line comment before "{".
 Function(a,// c
 {int b}) x;
@@ -210,7 +228,8 @@
 Function(
   a, { // c
   int b,
-}) x;
+})
+x;
 >>> Line comment after "{".
 Function({// c
 int arg}) x;
@@ -218,21 +237,24 @@
 Function({
   // c
   int arg,
-}) x;
+})
+x;
 >>> Line comment before "}".
 Function({int arg// c
 }) x;
 <<<
 Function({
   int arg, // c
-}) x;
+})
+x;
 >>> Line comment after "{".
 Function({int arg}// c
 ) x;
 <<<
 Function({
   int arg, // c
-}) x;
+})
+x;
 >>> Doc comment before first parameter.
 Function(/// c
 a,b) x;
@@ -241,7 +263,8 @@
   /// c
   a,
   b,
-) x;
+)
+x;
 >>> Doc comment before ",".
 Function(a/// c
 ,b) x;
@@ -251,7 +274,8 @@
 
   /// c
   b,
-) x;
+)
+x;
 >>> Doc comment after ",".
 Function(a,/// c
 b) x;
@@ -261,7 +285,8 @@
 
   /// c
   b,
-) x;
+)
+x;
 >>> Doc comment before "[".
 Function(a,/// c
 [b]) x;
@@ -272,7 +297,8 @@
 
   /// c
   b,
-]) x;
+])
+x;
 >>> Doc comment after "[".
 Function([/// c
 arg]) x;
@@ -280,7 +306,8 @@
 Function([
   /// c
   arg,
-]) x;
+])
+x;
 >>> Doc comment before "]".
 Function([arg/// c
 ]) x;
@@ -289,7 +316,8 @@
   arg,
 
   /// c
-]) x;
+])
+x;
 >>> Doc comment after "]".
 Function([arg]/// c
 ) x;
@@ -298,7 +326,8 @@
   arg,
 
   /// c
-]) x;
+])
+x;
 >>> Doc comment before "{".
 Function(a,/// c
 {int b}) x;
@@ -308,7 +337,8 @@
 
   /// c
   int b,
-}) x;
+})
+x;
 >>> Doc comment after "{".
 Function({/// c
 int arg}) x;
@@ -316,7 +346,8 @@
 Function({
   /// c
   int arg,
-}) x;
+})
+x;
 >>> Doc comment before "}".
 Function({int arg/// c
 }) x;
@@ -325,7 +356,8 @@
   int arg,
 
   /// c
-}) x;
+})
+x;
 >>> Doc comment after "{".
 Function({int arg}/// c
 ) x;
@@ -334,7 +366,8 @@
   int arg,
 
   /// c
-}) x;
+})
+x;
 >>> Comment before removed mandatory trailing comma.
 Function(a/* c */,) x;
 <<<
@@ -348,11 +381,12 @@
 <<<
 Function(a /* c1 */ /* c2 */) x;
 >>> Comment at inserted mandatory trailing comma.
-Function(veryLongParameterName/* c */) x;
+Function(veryLongParameterName__/* c */) x;
 <<<
 Function(
-  veryLongParameterName /* c */,
-) x;
+  veryLongParameterName__ /* c */,
+)
+x;
 >>> Comment before removed optional trailing comma.
 Function([a/* c */,]) x;
 <<<
@@ -370,7 +404,8 @@
 <<<
 Function([
   veryLongParameterName /* c */,
-]) x;
+])
+x;
 >>> Comment before removed named trailing comma.
 Function({int a/* c */,}) x;
 <<<
@@ -388,13 +423,15 @@
 <<<
 Function({
   int veryLongParameterName /* c */,
-}) x;
+})
+x;
 >>> Wrap inline Inline block comment.
 Function(/* a very long Inline block comment */) x;
 <<<
 Function(
   /* a very long Inline block comment */
-) x;
+)
+x;
 >>> Before parameter.
 Function(
     /* comment */ int a, int b, int c,
@@ -405,4 +442,5 @@
   int b,
   int c, [
   direction,
-]) x;
\ No newline at end of file
+])
+x;
\ No newline at end of file
diff --git a/test/tall/type/metadata.stmt b/test/tall/type/metadata.stmt
index 7fee437..f91c661 100644
--- a/test/tall/type/metadata.stmt
+++ b/test/tall/type/metadata.stmt
@@ -11,7 +11,8 @@
   int param2,
   @annotation int param3,
   int param4,
-) func;
+)
+func;
 >>> On unsplit record type field.
 (@a int, {@a double d}) record;
 <<<
@@ -23,4 +24,5 @@
   @anno @tation int,
   @annotation String s, {
   @annotation double d,
-}) record;
\ No newline at end of file
+})
+record;
\ No newline at end of file
diff --git a/test/tall/type/record.stmt b/test/tall/type/record.stmt
index 1906c30..80eeb88 100644
--- a/test/tall/type/record.stmt
+++ b/test/tall/type/record.stmt
@@ -37,25 +37,28 @@
 (
   VeryVeryLongType_____
   veryLongName___________________,
-) x;
+)
+x;
 >>> Split named positional fields.
 ( int  longValue  ,  String  veryVeryLongLabel  , ) x;
 <<<
 (
   int longValue,
   String veryVeryLongLabel,
-) x;
+)
+x;
 >>> Unsplit unnamed positional fields have no trailing comma.
 ( int    ,  String   ,  ) x;
 <<<
 (int, String) x;
 >>> Split only named fields.
-(  {  int  longValue  ,  String  veryLongLabel  ,  } ) x;
+(  {  int  longValue  ,  String  anotherLongLabel  ,  } ) x;
 <<<
 ({
   int longValue,
-  String veryLongLabel,
-}) x;
+  String anotherLongLabel,
+})
+x;
 >>> Empty record types don't split.
 someLongFunctionName__________________(() x) {}
 <<<
@@ -64,7 +67,8 @@
 ) {}
 >>> Unsplit short single positional field.
 (TypeName,
-) x;
+)
+x;
 <<<
 (TypeName,) x;
 >>> Unsplit single positional field.
@@ -72,14 +76,15 @@
 <<<
 (VeryLongTypeName________________,) x;
 >>> Split positional types.
-(TypeName,TypeName,TypeName,TypeName) x;
+(TypeName1,TypeName2,TypeName3,TypeName4) x;
 <<<
 (
-  TypeName,
-  TypeName,
-  TypeName,
-  TypeName,
-) x;
+  TypeName1,
+  TypeName2,
+  TypeName3,
+  TypeName4,
+)
+x;
 >>> Split named types.
 ({TypeName a,TypeName b,TypeName c,TypeName d}) x;
 <<<
@@ -88,7 +93,8 @@
   TypeName b,
   TypeName c,
   TypeName d,
-}) x;
+})
+x;
 >>> Split named if positional splits.
 (TypeName,TypeName,TypeName,TypeName,{TypeName a,TypeName b}) x;
 <<<
@@ -99,7 +105,8 @@
   TypeName, {
   TypeName a,
   TypeName b,
-}) x;
+})
+x;
 >>> Split positional if named splits.
 (TypeName,TypeName,{TypeName a,TypeName b,TypeName c,TypeName d}) x;
 <<<
@@ -110,7 +117,8 @@
   TypeName b,
   TypeName c,
   TypeName d,
-}) x;
+})
+x;
 >>> Single named field has no trailing comma.
 ({int n,}) x;
 <<<
@@ -130,7 +138,8 @@
     TypeName,
   ),
   TypeName,
-) x;
+)
+x;
 >>> Split outer type argument list if inner record splits.
 Map<String, (TypeName,TypeName,TypeName,TypeName)> map;
 <<<
@@ -142,4 +151,5 @@
     TypeName,
     TypeName,
   )
-> map;
\ No newline at end of file
+>
+map;
\ No newline at end of file
diff --git a/test/tall/type/record_comment.stmt b/test/tall/type/record_comment.stmt
index 7daee3d..0121fc5 100644
--- a/test/tall/type/record_comment.stmt
+++ b/test/tall/type/record_comment.stmt
@@ -7,7 +7,8 @@
   int // comment
   value,
   String label,
-) x;
+)
+x;
 >>> Comment after field and comma.
 (int value, // comment
 String label) x;
@@ -15,7 +16,8 @@
 (
   int value, // comment
   String label,
-) x;
+)
+x;
 >>> Comment before field and comma.
 (int value // comment
 ,String label) x;
@@ -23,25 +25,28 @@
 (
   int value, // comment
   String label,
-) x;
+)
+x;
 >>> Comment between positional and named delimiter.
 (int value, // comment
-{String label}) 
+{String label})
 x;
 <<<
 (
   int value, { // comment
   String label,
-}) x;
+})
+x;
 >>> Comment after named left delimiter.
 (int value, {  // comment
-String label}) 
+String label})
 x;
 <<<
 (
   int value, { // comment
   String label,
-}) x;
+})
+x;
 >>> Comment after named right delimiter.
 (int value, {String label}  // comment
 )
@@ -50,13 +55,15 @@
 (
   int value, {
   String label, // comment
-}) x;
+})
+x;
 >>> Comment between record type and nullable question mark.
 (int value  , ) // comment
 ? x;
 <<<
 (int value,) // comment
-? x;
+?
+x;
 >>> Comment after record type.
 (int value,     String label) // comment
 x;
diff --git a/test/tall/type/type_argument.stmt b/test/tall/type/type_argument.stmt
index 4feac3e..ecfbde9 100644
--- a/test/tall/type/type_argument.stmt
+++ b/test/tall/type/type_argument.stmt
@@ -10,7 +10,8 @@
   LongTypeName,
   AnotherLongType,
   ThirdOne
-> g;
+>
+g;
 >>> Splitting in type argument forces outer type argument list to split.
 Generic<Map<LongTypeName, AnotherReallyLongType>, ThirdOne> g;
 <<<
@@ -20,7 +21,8 @@
     AnotherReallyLongType
   >,
   ThirdOne
-> g;
+>
+g;
 >>> Nullable type argument.
 Map<  int  ?  , List<String  ?  > ? > m;
 <<<
@@ -40,4 +42,5 @@
     fourth,
     fifth,
   )
-> f;
\ No newline at end of file
+>
+f;
\ No newline at end of file
diff --git a/test/tall/variable/local.stmt b/test/tall/variable/local.stmt
index 9dffdca..a5ce5d7 100644
--- a/test/tall/variable/local.stmt
+++ b/test/tall/variable/local.stmt
@@ -124,7 +124,8 @@
 Generic<
   LongTypeArgument,
   AnotherLongTypeName
-> variable;
+>
+variable;
 >>> Prefer to split at "=" over infix operator.
 int variableName = argument * argument + argument;
 <<<