From 5c279a3dc8cd3fbd50d4468bbab743bb3d5fe482 Mon Sep 17 00:00:00 2001 From: Retheesh Date: Wed, 16 Feb 2022 14:33:24 +0800 Subject: [PATCH] Normalize generic types Fixes https://github.com/fsprojects/fantomas/issues/712 (but unfortunately creates a regression wrt units of measure) NOTE: rebasing from https://github.com/nblockchain/fantomless/commit/215d4eb1c41bbf7def86b705b135cf4e1d1e3f6a --- src/Fantomas.Tests/AttributeTests.fs | 1 + src/Fantomas.Tests/SignatureTests.fs | 52 +++++++++++++--------- src/Fantomas.Tests/TypeDeclarationTests.fs | 12 ++++- src/Fantomas.Tests/UnionTests.fs | 34 +++++++++++++- src/Fantomas/CodePrinter.fs | 26 ++++++----- src/Fantomas/Context.fs | 6 +++ 6 files changed, 97 insertions(+), 34 deletions(-) diff --git a/src/Fantomas.Tests/AttributeTests.fs b/src/Fantomas.Tests/AttributeTests.fs index 3522f2b050..b5623fac55 100644 --- a/src/Fantomas.Tests/AttributeTests.fs +++ b/src/Fantomas.Tests/AttributeTests.fs @@ -89,6 +89,7 @@ do () """ [] +[] let ``units of measures declaration`` () = formatSourceString false diff --git a/src/Fantomas.Tests/SignatureTests.fs b/src/Fantomas.Tests/SignatureTests.fs index b4e3c77ac9..a2b86c1de0 100644 --- a/src/Fantomas.Tests/SignatureTests.fs +++ b/src/Fantomas.Tests/SignatureTests.fs @@ -4,9 +4,9 @@ open NUnit.Framework open FsUnit open Fantomas.Tests.TestHelper -// the current behavior results in a compile error since "(string * string) list" is converted to "string * string list" +// the old behavior resulted in a compile error since "(string * string) list" was converted to "string * string list" [] -let ``should keep the (string * string) list type signature in records`` () = +let ``should understand the (string * string) list type signature in records`` () = formatSourceString false """type MSBuildParams = @@ -22,28 +22,40 @@ let ``should keep the (string * string) list type signature in records`` () = |> should equal """type MSBuildParams = - { Targets: string list - Properties: (string * string) list - MaxCpuCount: int option option - ToolsVersion: string option - Verbosity: MSBuildVerbosity option - FileLoggers: MSBuildFileLoggerConfig list option } + { Targets: list + Properties: list<(string * string)> + MaxCpuCount: option> + ToolsVersion: option + Verbosity: option + FileLoggers: option> } """ [] -let ``should keep the (string * string) list type signature in functions`` () = - shouldNotChangeAfterFormat - """ -let MSBuildWithProjectProperties outputPath (targets: string) (properties: string -> (string * string) list) projects = +let ``should understand the (string * string) list type signature in functions`` () = + formatSourceString + false + """let MSBuildWithProjectProperties outputPath (targets: string) (properties: string -> (string * string) list) projects = + doingsomstuff +""" + config + |> should + equal + """let MSBuildWithProjectProperties outputPath (targets: string) (properties: string -> list<(string * string)>) projects = doingsomstuff """ [] -let ``should keep the string * string list type signature in functions`` () = - shouldNotChangeAfterFormat - """ -let MSBuildWithProjectProperties outputPath (targets: string) (properties: (string -> string) * string list) projects = +let ``should understand the string * string list type signature in functions`` () = + formatSourceString + false + """let MSBuildWithProjectProperties outputPath (targets: string) (properties: (string -> string) * string list) projects = + doingsomstuff +""" + config + |> should + equal + """let MSBuildWithProjectProperties outputPath (targets: string) (properties: (string -> string) * list) projects = doingsomstuff """ @@ -70,7 +82,7 @@ let ``should not add parens in signature`` () = """ [] -let ``should keep the string * string * string option type signature`` () = +let ``should understand the string * string * string option type signature`` () = formatSourceString false """type DGML = @@ -83,11 +95,11 @@ let ``should keep the string * string * string option type signature`` () = equal """type DGML = | Node of string - | Link of string * string * (string option) + | Link of string * string * (option) """ [] -let ``should keep the (string option * Node) list type signature`` () = +let ``should understand the (string option * Node) list type signature`` () = formatSourceString false """type Node = @@ -100,7 +112,7 @@ let ``should keep the (string option * Node) list type signature`` () = equal """type Node = { Name: string; - NextNodes: (string option * Node) list } + NextNodes: list<(option * Node)> } """ [] diff --git a/src/Fantomas.Tests/TypeDeclarationTests.fs b/src/Fantomas.Tests/TypeDeclarationTests.fs index 18f6483f47..8284b0dee5 100644 --- a/src/Fantomas.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Tests/TypeDeclarationTests.fs @@ -2324,10 +2324,18 @@ and Variable<'model, 'msg> = [] let ``union type with constraint`` () = - formatSourceString false """type 'a t when 'a :> IDisposable = T of 'a option""" config + formatSourceString false """type 'a t when 'a :> IDisposable = T of option<'a>""" config |> should equal - """type 'a t when 'a :> IDisposable = T of 'a option + """type t<'a when 'a :> IDisposable> = T of option<'a> +""" + +[] +let ``union type with constraint (II)`` () = + formatSourceString false """type t<'a when 'a :> IDisposable> = T of option<'a>""" config + |> should + equal + """type t<'a when 'a :> IDisposable> = T of option<'a> """ [] diff --git a/src/Fantomas.Tests/UnionTests.fs b/src/Fantomas.Tests/UnionTests.fs index 7faa04cbd8..98a0739c2b 100644 --- a/src/Fantomas.Tests/UnionTests.fs +++ b/src/Fantomas.Tests/UnionTests.fs @@ -263,7 +263,7 @@ type CustomerId = """ [] -let ``generic type style should be respected`` () = +let ``generic type style should be improved, 712`` () = formatSourceString false """ @@ -274,7 +274,37 @@ type 'a Foo = Foo of 'a |> should equal """ -type 'a Foo = Foo of 'a +type Foo<'a> = Foo of 'a +""" + +[] +let ``generic type style should be improved (II), 712`` () = + formatSourceString + false + """ +type 'T Foo when 'T :> IDisposable = { Bar: 'T } + """ + config + |> prepend newline + |> should + equal + """ +type Foo<'T when 'T :> IDisposable> = { Bar: 'T } +""" + +[] +let ``generic type style should be improved (III), 712`` () = + formatSourceString + false + """ +type Foo<'T> = Bar of 'T option + """ + config + |> prepend newline + |> should + equal + """ +type Foo<'T> = Bar of option<'T> """ [] diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 5978db1e9b..d105645028 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -541,15 +541,17 @@ and genTypeAndParam astContext typeName (tds: SynTyparDecls option) tcs = +> colPre (!- " when ") wordAnd tcs (genTypeConstraint astContext) -- closeSep) - match tds with - | None -> !-typeName - | Some (SynTyparDecls.PostfixList (tds, tcs, _range)) -> !-typeName +> types "<" tds tcs ">" - | Some (SynTyparDecls.PrefixList (tds, _range)) -> types "(" tds [] ")" -- " " -- typeName - | Some (SynTyparDecls.SinglePrefix (td, _range)) -> - genTyparDecl { astContext with IsFirstTypeParam = true } td - +> sepSpace - -- typeName - +> colPre (!- " when ") wordAnd tcs (genTypeConstraint astContext) + let res, isSinglePrefix = + + match tds with + | None -> !-typeName, false + | Some (SynTyparDecls.PostfixList (tds, tcs, _range)) -> !-typeName +> types "<" tds tcs ">", false + | Some (SynTyparDecls.PrefixList (tds, _range)) -> types "(" tds [] ")" -- " " -- typeName, false + | Some (SynTyparDecls.SinglePrefix (td, _range)) -> + !-typeName +> types "<" [ td ] tcs ">", not (List.isEmpty tcs) + + res + +> ifElse isSinglePrefix sepNone (colPre (!- " when ") wordAnd tcs (genTypeConstraint astContext)) and genTypeParamPostfix astContext tds = match tds with @@ -4324,7 +4326,11 @@ and genType astContext outerBracket t = let postForm = match ts with | [] -> loop t - | [ t' ] -> loop t' +> sepSpace +> loop t + | [ t' ] -> + match t with + | SynType.LongIdent (LongIdentWithDots.LongIdentWithDots ([ lid ], _)) when lid.idText = "[]" -> + loop t' +> sepSpace +> loop t + | _ -> loop t +> sepOpenAng +> loop t' +> sepCloseAng | ts -> sepOpenT +> col sepComma ts loop diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 476c8ffb6b..c29aaaf896 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -776,6 +776,12 @@ let internal sepOpenT = !- "(" /// closing token of tuple let internal sepCloseT = !- ")" +/// opening angle bracket +let internal sepOpenAng = !- "<" + +/// closing angle bracket +let internal sepCloseAng = !- ">" + // we need to make sure each expression in the function application has offset at least greater than // indentation of the function expression itself // we replace sepSpace in such case