diff --git a/CHANGELOG.md b/CHANGELOG.md index fed0e6d520..04fec92d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 6.2.3 - 2023-11-2 + +### Fixed +* Crash when trying to format indexed property with three arguments. [#2971](https://github.com/fsprojects/fantomas/issues/2971) + ## 6.2.2 - 2023-10-18 ### Fixed diff --git a/src/Fantomas.Core.Tests/TypeDeclarationTests.fs b/src/Fantomas.Core.Tests/TypeDeclarationTests.fs index a61e67990e..64325a67eb 100644 --- a/src/Fantomas.Core.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Core.Tests/TypeDeclarationTests.fs @@ -3642,3 +3642,26 @@ type Meh class end """ + +[] +let ``multi tuple setter with indexer, 2971`` () = + formatSourceString + false + """ +type MyArray3 () = + member _.Item + with get (x: int, y: int, z: int) = + () + and set (x: int, y: int, z: int) v = + () +""" + config + |> prepend newline + |> should + equal + """ +type MyArray3() = + member _.Item + with get (x: int, y: int, z: int) = () + and set (x: int, y: int, z: int) v = () +""" diff --git a/src/Fantomas.Core/ASTTransformer.fs b/src/Fantomas.Core/ASTTransformer.fs index f71e0670bb..e4eb6cdd40 100644 --- a/src/Fantomas.Core/ASTTransformer.fs +++ b/src/Fantomas.Core/ASTTransformer.fs @@ -2661,24 +2661,27 @@ let mkPropertyGetSetBinding let pats = match ps with - | [ SynPat.Tuple(false, [ p1; p2; p3 ], [ comma ], _) ] -> - let mTuple = unionRanges p1.Range p2.Range - - [ PatParenNode( - stn "(" Range.Zero, - Pattern.Tuple( - PatTupleNode( - [ Choice1Of2(mkPat creationAide p1) - Choice2Of2(stn "," comma) - Choice1Of2(mkPat creationAide p2) ], - mTuple - ) - ), - stn ")" Range.Zero, - mTuple - ) - |> Pattern.Paren - mkPat creationAide p3 ] + | [ SynPat.Tuple(false, ps, commas, _) ] when + // This is the case for an indexer setter. + // The AST is weird in this case and doesn't properly reflect what the user wrote. + // It will represent `set (x: int, y: int, z: int) v` as a single tuple with 4 patterns and 2 commas. + ps.Length - 2 = commas.Length + -> + + let tuplePat = + let tuplePs = List.take (ps.Length - 1) ps + let mTuple = tuplePs |> List.map (fun p -> p.Range) |> List.reduce unionRanges + + match tuplePs with + // If there is only a single element, it does not need any additional parentheses. + | [ singlePat ] -> singlePat + | _ -> SynPat.Paren(SynPat.Tuple(false, tuplePs, commas, mTuple), mTuple) + |> mkPat creationAide + + [ tuplePat + match List.tryLast ps with + | None -> failwith "" + | Some indexerPat -> mkPat creationAide indexerPat ] | [ SynPat.Tuple(false, [ p1; p2 ], _, _) ] -> [ mkPat creationAide p1; mkPat creationAide p2 ] | ps -> List.map (mkPat creationAide) ps