diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs
index b7b4cce955f..6f2bcb62f80 100644
--- a/src/Compiler/Checking/NicePrint.fs
+++ b/src/Compiler/Checking/NicePrint.fs
@@ -1743,7 +1743,7 @@ module TastDefinitionPrinting =
let overallL = modifierAndMember ^^ (nameL |> addColonL) ^^ typL
layoutXmlDocOfPropInfo denv infoReader pinfo overallL
- let layoutTyconDefn (denv: DisplayEnv) (infoReader: InfoReader) ad m simplified typewordL (tcref: TyconRef) =
+ let layoutTyconDefn (denv: DisplayEnv) (infoReader: InfoReader) ad m simplified isFirstType (tcref: TyconRef) =
let g = denv.g
// use 4-indent
let (-*) = if denv.printVerboseSignatures then (-----) else (---)
@@ -1773,6 +1773,12 @@ module TastDefinitionPrinting =
else
None, tagUnknownType
+ let typewordL =
+ if isFirstType then
+ WordL.keywordType
+ else
+ wordL (tagKeyword "and") ^^ layoutAttribs denv start false tycon.TypeOrMeasureKind tycon.Attribs emptyL
+
let nameL = ConvertLogicalNameToDisplayLayout (tagger >> mkNav tycon.DefinitionRange >> wordL) tycon.DisplayNameCore
let nameL = layoutAccessibility denv tycon.Accessibility nameL
@@ -2124,7 +2130,7 @@ module TastDefinitionPrinting =
|> addLhs
typeDeclL
- |> layoutAttribs denv start false tycon.TypeOrMeasureKind tycon.Attribs
+ |> fun tdl -> if isFirstType then layoutAttribs denv start false tycon.TypeOrMeasureKind tycon.Attribs tdl else tdl
|> layoutXmlDocOfEntity denv infoReader tcref
// Layout: exception definition
@@ -2154,8 +2160,8 @@ module TastDefinitionPrinting =
| [] -> emptyL
| [h] when h.IsFSharpException -> layoutExnDefn denv infoReader (mkLocalEntityRef h)
| h :: t ->
- let x = layoutTyconDefn denv infoReader ad m false WordL.keywordType (mkLocalEntityRef h)
- let xs = List.map (mkLocalEntityRef >> layoutTyconDefn denv infoReader ad m false (wordL (tagKeyword "and"))) t
+ let x = layoutTyconDefn denv infoReader ad m false true (mkLocalEntityRef h)
+ let xs = List.map (mkLocalEntityRef >> layoutTyconDefn denv infoReader ad m false false) t
aboveListL (x :: xs)
let rec fullPath (mspec: ModuleOrNamespace) acc =
@@ -2267,7 +2273,7 @@ module TastDefinitionPrinting =
elif eref.IsFSharpException then
layoutExnDefn denv infoReader eref
else
- layoutTyconDefn denv infoReader ad m true WordL.keywordType eref
+ layoutTyconDefn denv infoReader ad m true true eref
//--------------------------------------------------------------------------
@@ -2561,7 +2567,7 @@ let layoutExnDef denv infoReader x = x |> TastDefinitionPrinting.layoutExnDefn d
let stringOfTyparConstraints denv x = x |> PrintTypes.layoutConstraintsWithInfo denv SimplifyTypes.typeSimplificationInfo0 |> showL
-let layoutTyconDefn denv infoReader ad m (* width *) x = TastDefinitionPrinting.layoutTyconDefn denv infoReader ad m true WordL.keywordType (mkLocalEntityRef x) (* |> Display.squashTo width *)
+let layoutTyconDefn denv infoReader ad m (* width *) x = TastDefinitionPrinting.layoutTyconDefn denv infoReader ad m true true (mkLocalEntityRef x) (* |> Display.squashTo width *)
let layoutEntityDefn denv infoReader ad m x = TastDefinitionPrinting.layoutEntityDefn denv infoReader ad m x
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
index 75e0f8a0323..6203b71fd6f 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
+++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
@@ -204,6 +204,7 @@
+
diff --git a/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs b/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs
new file mode 100644
index 00000000000..d7f81a04f50
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs
@@ -0,0 +1,77 @@
+module FSharp.Compiler.ComponentTests.Signatures.TypeTests
+
+open Xunit
+open FsUnit
+open FSharp.Test.Compiler
+open FSharp.Compiler.ComponentTests.Signatures.TestHelpers
+
+[]
+let ``Recursive type with attribute`` () =
+ FSharp
+ """
+namespace Foo.Types
+
+open System.Collections.Generic
+
+type FormatSelectionRequest =
+ {
+ SourceCode: string
+ /// File path will be used to identify the .editorconfig options
+ /// Unless the configuration is passed
+ FilePath: string
+ /// Overrides the found .editorconfig.
+ Config: IReadOnlyDictionary option
+ /// Range follows the same semantics of the FSharp Compiler Range type.
+ Range: FormatSelectionRange
+ }
+
+ member this.IsSignatureFile = this.FilePath.EndsWith(".fsi")
+
+and FormatSelectionRange =
+ struct
+ val StartLine: int
+ val StartColumn: int
+ val EndLine: int
+ val EndColumn: int
+
+ new(startLine: int, startColumn: int, endLine: int, endColumn: int) =
+ { StartLine = startLine
+ StartColumn = startColumn
+ EndLine = endLine
+ EndColumn = endColumn }
+ end
+"""
+ |> printSignatures
+ |> prependNewline
+ |> should equal
+ """
+namespace Foo.Types
+
+ type FormatSelectionRequest =
+ {
+ SourceCode: string
+
+ /// File path will be used to identify the .editorconfig options
+ /// Unless the configuration is passed
+ FilePath: string
+
+ /// Overrides the found .editorconfig.
+ Config: System.Collections.Generic.IReadOnlyDictionary option
+
+ /// Range follows the same semantics of the FSharp Compiler Range type.
+ Range: FormatSelectionRange
+ }
+
+ member IsSignatureFile: bool
+
+ and [] FormatSelectionRange =
+
+ new: startLine: int * startColumn: int * endLine: int * endColumn: int -> FormatSelectionRange
+
+ val StartLine: int
+
+ val StartColumn: int
+
+ val EndLine: int
+
+ val EndColumn: int"""