fantomas icon indicating copy to clipboard operation
fantomas copied to clipboard

Type abbreviation is wrongly formatted

Open nojaf opened this issue 4 years ago • 1 comments

Issue created from fantomas-online

Code

  type GetParseResultsForFile = string<LocalPath> -> FSharp.Compiler.Text.Position -> Async<ResultOrString<ParseAndCheckResults * string * FSharp.Compiler.Text.ISourceText>>

Result

type GetParseResultsForFile =
    string<LocalPath>
        -> FSharp.Compiler.Text.Position
        -> Async<ResultOrString<ParseAndCheckResults * string * FSharp.Compiler.Text.ISourceText>>

Problem description

Given the recent guidance of the style guide, I would expect that the result should be:

type GetParseResultsForFile =
    string<LocalPath> ->
    FSharp.Compiler.Text.Position ->
        Async<ResultOrString<ParseAndCheckResults * string * FSharp.Compiler.Text.ISourceText>>

However, this leads to invalid code: example

@dsyme any idea why this is happening?

Extra information

  • [ ] The formatted result breaks by code.
  • [ ] The formatted result gives compiler warnings.
  • [ ] I or my company would be willing to help fix this.

Options

Fantomas 4.6 branch at 1/1/1990

Default Fantomas configuration

Did you know that you can ignore files when formatting from fantomas-tool or the FAKE targets by using a .fantomasignore file?

nojaf avatar Jan 08 '22 11:01 nojaf

Hmmm I see. We only tested val declarations, e.g.

val F:
    A ->
    B ->
      C

and not type abbreviations:

type X =
    A ->
    B ->
      C

It seems value signatures can use end-of-line -> without indentation of the next line, but types themselves can't

(Note, the thing on the right of a val or member declaration is a value signature, parsed with different parsing rules to a type)

I'm having trouble determining exactly which types this applies to.

  1. The restriction does apply to types inside value signatures, e.g. this will produce an error
// Gives an error
val GetParseResultsForFile :
    (A ->
     B ->
      C)
  1. The restriction does not apply to outermost types in record declarations
// Does not give an error
type R =
    { F: A ->
         B ->
            C }

but does apply to inner types:

// Gives an error
type R =
    { F: (A ->
          B ->
            C) }
  1. The restriction does not apply to the right hand side of function types, e.g. only the outer most position of type abbreviations or parenthesized types:
/// Does not give an error
type X =
    A ->
      B ->
      C ->
      D

/// Does not give an error
val F :
   (A ->
      B ->
      C ->
      D)

I think the safest assumption is to make indent happen for the B part of a multi-line "A -> B" when

A. the type occurs on the right of a type abbreviation, OR B. the type occurs in parentheses

However I guess we should systematically test all other locations where types can occur in the grammar. I'm not actually sure of the problem, I guess it must be a missing rule in the grammar to deal with the offside thing inserted after the ->, but one that is only kicking in for types in very specific locations.

dsyme avatar Jan 11 '22 18:01 dsyme