fsprojects / fantomas

FSharp source code formatter
https://fsprojects.github.io/fantomas
Other
758 stars 189 forks source link

Incorrect line split when using a custom operator #2107

Open chausner opened 2 years ago

chausner commented 2 years ago

Issue created from fantomas-online

Code

let inline (%%) x y = ((x % y) + y) % y

let aVeryLongVariableName = 0

let a = (if aVeryLongVariableName = 0 then 1 else -1) %% 4

Result

let inline (%%) x y = ((x % y) + y) % y

let aVeryLongVariableName = 0

let a =
    (if aVeryLongVariableName = 0 then
         1
     else
         -1)

    %% 4

Problem description

Fantomas incorrectly moves the custom %% operator to a new line which makes the code not compile anymore.

Extra information

Options

Fantomas master branch at 1/1/1990

Default Fantomas configuration

nojaf commented 2 years ago

Hello @chausner, thank you for reporting this problem.

This one is interesting on a couple of levels:

I'm not sure how to tackle this one, to be honest. You could increase fsharp_max_if_then_else_short_width to work around the problem. Sample

chausner commented 2 years ago

You could increase fsharp_max_if_then_else_short_width to work around the problem.

Yes, that should work as a workaround in this case but the problem does not seem to be related to if..then..else as it also occurs in this somewhat contrived example:

let inline (%%) x y = ((x % y) + y) % y

let a = 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5 %% 5

which gets formatted to

let inline (%%) x y = ((x % y) + y) % y

let a =
    5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5
    %% 5

Other operators don't seem to have this problem, I wonder why.

I see the same issue with the modulo operator. The following is not accepted by the F# compiler:

let b =
    5
    % 5

But replacing the operator with +, it is valid. So it seems there are certain operators which may be put onto a separate line and others may not.

chausner commented 2 years ago

So it seems there are certain operators which may be put onto a separate line and others may not.

I investigated this a bit further and found that from the following operators:

+ - * / % %% ** < <= > >= <> = && || &&& <<< >>> ^^^ ||| ~~~

only these operators are not accepted on a new line:

% %% < > =

For % and %%, the compiler (incorrectly?) recognizes the operators as (~%) and (~%%), defined in https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-extratopleveloperators.html.

For <, > and =, the compiler fails with a more generic FS0010 error.

I wonder if this behavior is by design or a compiler bug. I created https://github.com/dotnet/fsharp/issues/12754 to clarify.

nojaf commented 2 years ago

Thank you for following up on this.