From ea96cd79593a1ee9841c355110e4754fd689883a Mon Sep 17 00:00:00 2001 From: Retheesh Date: Fri, 17 Sep 2021 10:51:22 +0800 Subject: [PATCH] Normalize generic types Fixes https://github.com/fsprojects/fantomas/issues/712 (but unfortunately creates a regression wrt units of measure) --- 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 | 14 +++--- src/Fantomas/Context.fs | 6 +++ 6 files changed, 87 insertions(+), 32 deletions(-) diff --git a/src/Fantomas.Tests/AttributeTests.fs b/src/Fantomas.Tests/AttributeTests.fs index 6e4de5767a..327e6d1c37 100644 --- a/src/Fantomas.Tests/AttributeTests.fs +++ b/src/Fantomas.Tests/AttributeTests.fs @@ -90,6 +90,7 @@ do () """ [] +[] let ``units of measures declaration`` () = formatSourceString false diff --git a/src/Fantomas.Tests/SignatureTests.fs b/src/Fantomas.Tests/SignatureTests.fs index d399128ca9..8cbbbfc38e 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 """ @@ -71,7 +83,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 = @@ -84,11 +96,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 = @@ -102,7 +114,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 d10e7b6a19..f25825f668 100644 --- a/src/Fantomas.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Tests/TypeDeclarationTests.fs @@ -2275,10 +2275,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 69ce4914d9..d2d81d9042 100644 --- a/src/Fantomas.Tests/UnionTests.fs +++ b/src/Fantomas.Tests/UnionTests.fs @@ -267,7 +267,7 @@ type CustomerId = """ [] -let ``generic type style should be respected`` () = +let ``generic type style should be improved, 712`` () = formatSourceString false """ @@ -278,7 +278,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 352fd0ba66..75d624bede 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -583,13 +583,7 @@ and genTypeAndParam astContext typeName tds tcs preferPostfix = elif preferPostfix then !-typeName +> types "<" ">" elif List.atMostOne tds then - genTyparDecl - { astContext with - IsFirstTypeParam = true } - (List.head tds) - +> sepSpace - -- typeName - +> colPre (!- " when ") wordAnd tcs (genTypeConstraint astContext) + !-typeName +> types "<" ">" else types "(" ")" -- " " -- typeName @@ -4251,7 +4245,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 46333fec70..d32e6295e5 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -784,6 +784,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