Skip to content

Commit 48ef9cb

Browse files
Add "%%" to noBreakInfixOps to fix soundness bug with custom %% operator
The custom %% operator (and the built-in F# quotation splice operators %% and %%) can be interpreted by the F# parser as unary prefix operators when they appear at the start of a new line. This caused Fantomas to produce invalid F# code by placing the operator on a new line. The fix adds "%%" to the noBreakInfixOps set, which keeps the operator on the same line as its left-hand-side expression (with the right-hand-side indented below if needed), matching the existing behaviour for %, =, <, >. Fixes #2107 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9e8ba5d commit 48ef9cb

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

src/Fantomas.Core.Tests/OperatorTests.fs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,29 @@ let hasUnEvenAmount regex line =
493493
- Regex.Matches(line, "\\\\" + regex).Count) % 2 = 1
494494
"""
495495

496+
[<Test>]
497+
let ``custom double-percent operator stays on same line as lhs when expression is too long, 2107`` () =
498+
formatSourceString
499+
"""
500+
let inline (%%) x y = ((x % y) + y) % y
501+
let aVeryLongVariableNameThatForceLineBreaking = 0
502+
let a = (if aVeryLongVariableNameThatForceLineBreaking = 0 then 1 else -1) %% 4
503+
"""
504+
config
505+
|> prepend newline
506+
|> should
507+
equal
508+
"""
509+
let inline (%%) x y = ((x % y) + y) % y
510+
let aVeryLongVariableNameThatForceLineBreaking = 0
511+
512+
let a =
513+
(if aVeryLongVariableNameThatForceLineBreaking = 0 then
514+
1
515+
else
516+
-1) %% 4
517+
"""
518+
496519
[<Test>]
497520
let ``parameter after multiline string, 783`` () =
498521
formatSourceString

src/Fantomas.Core/CodePrinter.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ open Fantomas.Core.Context
55
open Fantomas.Core.SyntaxOak
66
open Microsoft.FSharp.Core.CompilerServices
77

8-
let noBreakInfixOps = set [| "="; ">"; "<"; "%" |]
8+
let noBreakInfixOps = set [| "="; ">"; "<"; "%"; "%%" |]
99
let newLineInfixOps = set [ "|>"; "||>"; "|||>"; ">>"; ">>=" ]
1010

1111
let rec (|UppercaseType|LowercaseType|) (t: Type) : Choice<unit, unit> =

0 commit comments

Comments
 (0)