@@ -145,6 +145,106 @@ let main _ =
145145 |> withStdOutContains " custom-du"
146146 |> withStdOutContains " custom-record"
147147
148+ [<Fact>]
149+ let ``Union field shapes : multiple fields versus a single tuple field`` () =
150+ FSharp """
151+ module Test
152+ type TwoFields = | Two of int * int
153+ type OneTupleField = | OneTup of (int * int)
154+ type NamedFields = | Named of x: int * y: int
155+
156+ [<EntryPoint>]
157+ let main _ =
158+ Two (1, 2) |> string |> System.Console.WriteLine
159+ OneTup (1, 2) |> string |> System.Console.WriteLine // a single tuple field keeps its own parens
160+ Named (1, 2) |> string |> System.Console.WriteLine // named fields render positionally, names are not shown
161+ 0
162+ """
163+ |> asExe
164+ |> withOptions [ " --reflectionfree" ]
165+ |> compileExeAndRun
166+ |> shouldSucceed
167+ |> withStdOutContains " Two(1, 2)"
168+ |> withStdOutContains " OneTup((1, 2))"
169+ |> withStdOutContains " Named(1, 2)"
170+
171+ [<Fact>]
172+ let ``Explicit field names do not change the rendering`` () =
173+ FSharp """
174+ module Test
175+ type Labelled = | WithNames of first: int * second: string
176+ type Plain = | WithoutNames of int * string
177+
178+ [<EntryPoint>]
179+ let main _ =
180+ WithNames (1, "a") |> string |> System.Console.WriteLine
181+ WithoutNames (1, "a") |> string |> System.Console.WriteLine // unnamed fields render the same way as named ones
182+ 0
183+ """
184+ |> asExe
185+ |> withOptions [ " --reflectionfree" ]
186+ |> compileExeAndRun
187+ |> shouldSucceed
188+ |> withStdOutContains " WithNames(1, a)"
189+ |> withStdOutContains " WithoutNames(1, a)"
190+
191+ [<Fact>]
192+ let ``Struct unions and struct records get a generated ToString`` () =
193+ FSharp """
194+ module Test
195+ [<Struct>] type StructUnion = | SA of a: int
196+ [<Struct>] type StructRecord = { SX: int; SY: int }
197+
198+ [<EntryPoint>]
199+ let main _ =
200+ SA 7 |> string |> System.Console.WriteLine
201+ { SX = 1; SY = 2 } |> string |> System.Console.WriteLine
202+ 0
203+ """
204+ |> asExe
205+ |> withOptions [ " --reflectionfree" ]
206+ |> compileExeAndRun
207+ |> shouldSucceed
208+ |> withStdOutContains " SA(7)"
209+ |> withStdOutContains " { SX = 1; SY = 2 }"
210+
211+ [<Fact>]
212+ let ``Anonymous records get a generated single - line ToString`` () =
213+ FSharp """
214+ module Test
215+ [<EntryPoint>]
216+ let main _ =
217+ {| A = 1; B = "hi" |} |> string |> System.Console.WriteLine
218+ (struct {| A = 1; B = "hi" |}) |> string |> System.Console.WriteLine // a struct anonymous record renders identically
219+ 0
220+ """
221+ |> asExe
222+ |> withOptions [ " --reflectionfree" ]
223+ |> compileExeAndRun
224+ |> shouldSucceed
225+ |> withStdOutContains " {| A = 1; B = hi |}"
226+
227+ [<Fact>]
228+ let ``Recursively defined types render when the data is finite`` () =
229+ FSharp """
230+ module Test
231+ type Tree = | Leaf | Node of Tree * int * Tree
232+ type TreeNode = { Value: int; Parent: TreeNode option } // an upward-only parent pointer stays finite
233+
234+ [<EntryPoint>]
235+ let main _ =
236+ Node (Node (Leaf, 1, Leaf), 2, Leaf) |> string |> System.Console.WriteLine
237+ let root = { Value = 0; Parent = None }
238+ { Value = 1; Parent = Some root } |> string |> System.Console.WriteLine
239+ 0
240+ """
241+ |> asExe
242+ |> withOptions [ " --reflectionfree" ]
243+ |> compileExeAndRun
244+ |> shouldSucceed
245+ |> withStdOutContains " Node(Node(Leaf, 1, Leaf), 2, Leaf)"
246+ |> withStdOutContains " { Value = 1; Parent = Some({ Value = 0; Parent = null }) }"
247+
148248[<Fact>]
149249let ``No debug display attribute`` () =
150250 someCode
0 commit comments