From 7fb1c611c4debc582cd3d91a6063eaf665178a54 Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 08:14:38 +0200 Subject: [PATCH 1/9] Add failing tests for anonymous record FSI printing (#6116) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../FSharp.Compiler.ComponentTests.fsproj | 1 + .../InteractiveSession/AnonRecordPrinting.fs | 120 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 954c02b8aca..9890126f895 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -388,6 +388,7 @@ + diff --git a/tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs b/tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs new file mode 100644 index 00000000000..98bec6b85e0 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +/// Tests for FSI pretty-printing of anonymous records (regression for dotnet/fsharp#6116). +/// Anonymous records must be printed with `{| |}` braces, distinct from nominal records which use `{ }`. +namespace InteractiveSession + +open Xunit +open FSharp.Test.Compiler + +module AnonRecordPrinting = + + // --- Anonymous records: must use {| |} --- + + // NOTE: Assertions target the VALUE portion (after `=`) only, because the + // `val it: ...` type-annotation already contains `{| ... |}` for anon + // record types regardless of the value-printing bug being fixed here. + + [] + let ``Anonymous record prints with bar braces``() = + Fsx """ +let r = {| Name = "Phillip"; Age = 28 |};; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + |> withStdOutContains "= {| Age = 28; Name = \"Phillip\" |}" + |> ignore + + [] + let ``Anonymous record with single field prints with bar braces``() = + Fsx """ +{| X = 1 |};; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + |> withStdOutContains "= {| X = 1 |}" + |> ignore + + [] + let ``Nested anonymous record prints with bar braces at both levels``() = + Fsx """ +{| Inner = {| X = 1 |} |};; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + // Both outer and inner record values must use bar-braces. + |> withStdOutContains "= {| Inner = {| X = 1 |} |}" + |> ignore + + [] + let ``Struct anonymous record prints with struct keyword and bar braces``() = + Fsx """ +struct {| X = 1; Y = 2 |};; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + |> withStdOutContains "= struct {| X = 1; Y = 2 |}" + |> ignore + + // --- Nominal records: must KEEP printing with { } (regression guard) --- + + [] + let ``Nominal record still prints with plain braces and not bar braces``() = + Fsx """ +type R = { Name: string; Age: int } +let r = { Name = "Phillip"; Age = 28 };; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + |> withStdOutContains "{ Name = \"Phillip\"" + |> withStdOutContains "Age = 28 }" + |> ignore + + // --- Other shapes must be unchanged (regression guard) --- + + [] + let ``Tuple printing unchanged``() = + Fsx """ +(1, "x");; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + |> withStdOutContains "(1, \"x\")" + |> ignore + + [] + let ``Discriminated union printing unchanged``() = + Fsx """ +type DU = A of int | B of string +A 42;; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + |> withStdOutContains "A 42" + |> ignore + + [] + let ``List printing unchanged``() = + Fsx """ +[1; 2; 3];; +() +""" + |> withOptions ["--nologo"] + |> runFsi + |> shouldSucceed + |> withStdOutContains "[1; 2; 3]" + |> ignore From 3aadd4a30f1efac926266b9110a93dffd81252dd Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 09:01:44 +0200 Subject: [PATCH 2/9] Fix FSI pretty printing for anonymous records (#6116) Anonymous records were rendered with { } braces, identical to nominal records, because FSharpType.IsRecord returns true for both. Detect the anonymous case via the CLR name prefix `<>f__AnonymousType` and thread an isAnonRecord flag through ValueInfo.RecordValue / recordValueL / makeRecordL so they emit the already-defined leftBraceBar / rightBraceBar punctuation literals ({| / |}). For anonymous records use a semicolon-separated horizontal layout (semiListL) instead of the vertical aboveListL used by nominal records - this matches how anon records are written in source. Struct anonymous records (compiled to value-type variants of <>f__AnonymousType) are detected at the same place via reprty.IsValueType, carried on ValueInfo.RecordValue as isStruct, and rendered with the existing struct keyword layout inside recordValueL (mirroring how tupleValueL handles TupleType.Value). The leftBraceBar / rightBraceBar literal definitions were moved out of the #if COMPILER block in TaggedText so they are also available in the FSharp.Core build of sformat.fs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Utilities/sformat.fs | 38 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/Compiler/Utilities/sformat.fs b/src/Compiler/Utilities/sformat.fs index 6ba5b68c462..8886acfaa5c 100644 --- a/src/Compiler/Utilities/sformat.fs +++ b/src/Compiler/Utilities/sformat.fs @@ -149,6 +149,8 @@ module TaggedText = let rightBracket = tagPunctuation "]" let leftBrace = tagPunctuation "{" let rightBrace = tagPunctuation "}" + let leftBraceBar = tagPunctuation "{|" + let rightBraceBar = tagPunctuation "|}" let equals = tagOperator "=" #if COMPILER @@ -216,8 +218,6 @@ module TaggedText = // common tagged literals let lineBreak = tagLineBreak "\n" let space = tagSpace " " - let leftBraceBar = tagPunctuation "{|" - let rightBraceBar = tagPunctuation "|}" let arrow = tagPunctuation "->" let dot = tagPunctuation "." let leftAngle = tagPunctuation "<" @@ -491,7 +491,7 @@ module ReflectUtils = type ValueInfo = | TupleValue of TupleType * (obj * Type)[] | FunctionClosureValue of Type - | RecordValue of (string * obj * Type)[] + | RecordValue of isAnonRecord: bool * isStruct: bool * (string * obj * Type)[] | UnionCaseValue of string * (string * (obj * Type))[] | ExceptionValue of Type * (string * (obj * Type))[] | NullValue @@ -555,7 +555,14 @@ module ReflectUtils = elif FSharpType.IsRecord(reprty, bindingFlags) then let props = FSharpType.GetRecordFields(reprty, bindingFlags) + let isAnonRecord = + reprty.Name.StartsWith("<>f__AnonymousType", StringComparison.Ordinal) + + let isStruct = isAnonRecord && reprty.IsValueType + RecordValue( + isAnonRecord, + isStruct, props |> Array.map (fun prop -> prop.Name, prop.GetValue(obj, null), prop.PropertyType) ) @@ -861,13 +868,24 @@ module Display = let unitL = wordL (tagPunctuation "()") - let makeRecordL nameXs = + let makeRecordL isAnonRecord nameXs = let itemL (name, xL) = (wordL name ^^ wordL equals) -- xL let braceL xs = - (wordL leftBrace) ^^ xs ^^ (wordL rightBrace) + if isAnonRecord then + (wordL leftBraceBar) ^^ xs ^^ (wordL rightBraceBar) + else + (wordL leftBrace) ^^ xs ^^ (wordL rightBrace) + + let itemLayouts = nameXs |> List.map itemL - nameXs |> List.map itemL |> aboveListL |> braceL + let body = + if isAnonRecord then + semiListL itemLayouts + else + aboveListL itemLayouts + + braceL body let makePropertiesL nameXs = let itemL (name, v) = @@ -1200,12 +1218,14 @@ module Display = | TupleType.Value -> structL ^^ fields | TupleType.Reference -> fields - and recordValueL depthLim items = + and recordValueL depthLim isAnonRecord isStruct items = let itemL (name, x, ty) = countNodes 1 tagRecordField name, nestedObjL depthLim Precedence.BracketIfTuple (x, ty) - makeRecordL (List.map itemL items) + let body = makeRecordL isAnonRecord (List.map itemL items) + + if isStruct then structL -- body else body and listValueL depthLim constr recd = match constr with @@ -1471,7 +1491,7 @@ module Display = match repr with | TupleValue(tupleType, vals) -> tupleValueL depthLim prec vals tupleType - | RecordValue items -> recordValueL depthLim (Array.toList items) + | RecordValue(isAnonRecord, isStruct, items) -> recordValueL depthLim isAnonRecord isStruct (Array.toList items) | UnionCaseValue(constr, recd) when // x is List. Note: "null" is never a valid list value. (not (isNull x)) && isListType (x.GetType()) From 13709359c6f45cf4ed8e6596463ed53f59ab15ee Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 9 Jun 2026 11:14:40 +0200 Subject: [PATCH 3/9] Add release notes for FSI anon-record printing fix (#6116) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 965957dbc0c..8cb3b46eca1 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -75,6 +75,7 @@ ([PR #19724](https://github.com/dotnet/fsharp/pull/19724)) * Emit debug points at a stack-empty position ([PR #19877](https://github.com/dotnet/fsharp/pull/19877)) * Fix spurious XmlDoc warnings (unknown parameter / no documentation for parameter) under `--warnon:3390` when a get/set property documents the full parameter set across both accessors. ([Issue #13684](https://github.com/dotnet/fsharp/issues/13684), [PR #19884](https://github.com/dotnet/fsharp/pull/19884)) +* Fix FSI pretty printing to distinguish anonymous records (`{| ... |}`) from nominal records (`{ ... }`). ([Issue #6116](https://github.com/dotnet/fsharp/issues/6116)) ### Added From a299076f36fa6075bc4396ffb94662fe358da429 Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 12:39:24 +0200 Subject: [PATCH 4/9] Refactor anon record printing: RecordKind DU, revert to aboveListL (#6116) Address CODE-QUALITY verifier feedback: 1. Replace `RecordValue of isAnonRecord: bool * isStruct: bool * ...` with a 3-case `RecordKind = Nominal | AnonReference | AnonStruct` so the impossible (isAnonRecord=false, isStruct=true) state is unrepresentable. Construction and consumption now use exhaustive matches. 2. Revert `semiListL` back to `aboveListL` for anon records. The list-combinator change was outside the original bug scope; the layout engine already chooses single-line rendering when content fits, so the only meaningful diff for anon records remains the brace tokens. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Utilities/sformat.fs | 52 +++++++++++++++++-------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/Compiler/Utilities/sformat.fs b/src/Compiler/Utilities/sformat.fs index 8886acfaa5c..15f7a06a121 100644 --- a/src/Compiler/Utilities/sformat.fs +++ b/src/Compiler/Utilities/sformat.fs @@ -487,11 +487,17 @@ module ReflectUtils = | Value | Reference + [] + type RecordKind = + | Nominal + | AnonReference + | AnonStruct + [] type ValueInfo = | TupleValue of TupleType * (obj * Type)[] | FunctionClosureValue of Type - | RecordValue of isAnonRecord: bool * isStruct: bool * (string * obj * Type)[] + | RecordValue of kind: RecordKind * (string * obj * Type)[] | UnionCaseValue of string * (string * (obj * Type))[] | ExceptionValue of Type * (string * (obj * Type))[] | NullValue @@ -555,14 +561,17 @@ module ReflectUtils = elif FSharpType.IsRecord(reprty, bindingFlags) then let props = FSharpType.GetRecordFields(reprty, bindingFlags) - let isAnonRecord = - reprty.Name.StartsWith("<>f__AnonymousType", StringComparison.Ordinal) - - let isStruct = isAnonRecord && reprty.IsValueType + let kind = + if reprty.Name.StartsWith("<>f__AnonymousType", StringComparison.Ordinal) then + if reprty.IsValueType then + RecordKind.AnonStruct + else + RecordKind.AnonReference + else + RecordKind.Nominal RecordValue( - isAnonRecord, - isStruct, + kind, props |> Array.map (fun prop -> prop.Name, prop.GetValue(obj, null), prop.PropertyType) ) @@ -868,24 +877,18 @@ module Display = let unitL = wordL (tagPunctuation "()") - let makeRecordL isAnonRecord nameXs = + let makeRecordL kind nameXs = let itemL (name, xL) = (wordL name ^^ wordL equals) -- xL let braceL xs = - if isAnonRecord then - (wordL leftBraceBar) ^^ xs ^^ (wordL rightBraceBar) - else - (wordL leftBrace) ^^ xs ^^ (wordL rightBrace) + match kind with + | RecordKind.AnonReference + | RecordKind.AnonStruct -> (wordL leftBraceBar) ^^ xs ^^ (wordL rightBraceBar) + | RecordKind.Nominal -> (wordL leftBrace) ^^ xs ^^ (wordL rightBrace) let itemLayouts = nameXs |> List.map itemL - let body = - if isAnonRecord then - semiListL itemLayouts - else - aboveListL itemLayouts - - braceL body + braceL (aboveListL itemLayouts) let makePropertiesL nameXs = let itemL (name, v) = @@ -1218,14 +1221,17 @@ module Display = | TupleType.Value -> structL ^^ fields | TupleType.Reference -> fields - and recordValueL depthLim isAnonRecord isStruct items = + and recordValueL depthLim kind items = let itemL (name, x, ty) = countNodes 1 tagRecordField name, nestedObjL depthLim Precedence.BracketIfTuple (x, ty) - let body = makeRecordL isAnonRecord (List.map itemL items) + let body = makeRecordL kind (List.map itemL items) - if isStruct then structL -- body else body + match kind with + | RecordKind.AnonStruct -> structL -- body + | RecordKind.AnonReference + | RecordKind.Nominal -> body and listValueL depthLim constr recd = match constr with @@ -1491,7 +1497,7 @@ module Display = match repr with | TupleValue(tupleType, vals) -> tupleValueL depthLim prec vals tupleType - | RecordValue(isAnonRecord, isStruct, items) -> recordValueL depthLim isAnonRecord isStruct (Array.toList items) + | RecordValue(kind, items) -> recordValueL depthLim kind (Array.toList items) | UnionCaseValue(constr, recd) when // x is List. Note: "null" is never a valid list value. (not (isNull x)) && isListType (x.GetType()) From baeace5d79070b8499ef14e8e7bce2f96c996fcc Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 12:56:33 +0200 Subject: [PATCH 5/9] Align AnonRecord test assertions with multi-line layout (#6116) After reverting recordValueL to aboveListL, multi-field anon records print across multiple lines. Split single-line substring assertions into opener/closer pairs (mirroring the nominal-record test) so the multi-line layout is accepted. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../InteractiveSession/AnonRecordPrinting.fs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs b/tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs index 98bec6b85e0..51e39dda0fc 100644 --- a/tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs +++ b/tests/FSharp.Compiler.ComponentTests/InteractiveSession/AnonRecordPrinting.fs @@ -17,6 +17,9 @@ module AnonRecordPrinting = [] let ``Anonymous record prints with bar braces``() = + // The layout engine may break multi-field records across lines, so the + // opening and closing bar-braces are checked separately (mirrors the + // approach used by the nominal-record test below). Fsx """ let r = {| Name = "Phillip"; Age = 28 |};; () @@ -24,7 +27,8 @@ let r = {| Name = "Phillip"; Age = 28 |};; |> withOptions ["--nologo"] |> runFsi |> shouldSucceed - |> withStdOutContains "= {| Age = 28; Name = \"Phillip\" |}" + |> withStdOutContains "= {| Age = 28" + |> withStdOutContains "Name = \"Phillip\" |}" |> ignore [] @@ -54,6 +58,8 @@ let r = {| Name = "Phillip"; Age = 28 |};; [] let ``Struct anonymous record prints with struct keyword and bar braces``() = + // The layout engine may break multi-field records across lines, so the + // `struct {|` opener and the `|}` closer are checked separately. Fsx """ struct {| X = 1; Y = 2 |};; () @@ -61,7 +67,8 @@ struct {| X = 1; Y = 2 |};; |> withOptions ["--nologo"] |> runFsi |> shouldSucceed - |> withStdOutContains "= struct {| X = 1; Y = 2 |}" + |> withStdOutContains "= struct {| X = 1" + |> withStdOutContains "Y = 2 |}" |> ignore // --- Nominal records: must KEEP printing with { } (regression guard) --- From 8cdea748e3e9780fedd04199b861e9f8160493b3 Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 13:40:00 +0200 Subject: [PATCH 6/9] Add PR link to release notes (#6116) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 8cb3b46eca1..a4ddb66302e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -75,7 +75,7 @@ ([PR #19724](https://github.com/dotnet/fsharp/pull/19724)) * Emit debug points at a stack-empty position ([PR #19877](https://github.com/dotnet/fsharp/pull/19877)) * Fix spurious XmlDoc warnings (unknown parameter / no documentation for parameter) under `--warnon:3390` when a get/set property documents the full parameter set across both accessors. ([Issue #13684](https://github.com/dotnet/fsharp/issues/13684), [PR #19884](https://github.com/dotnet/fsharp/pull/19884)) -* Fix FSI pretty printing to distinguish anonymous records (`{| ... |}`) from nominal records (`{ ... }`). ([Issue #6116](https://github.com/dotnet/fsharp/issues/6116)) +* Fix FSI pretty printing to distinguish anonymous records (`{| ... |}`) from nominal records (`{ ... }`). ([Issue #6116](https://github.com/dotnet/fsharp/issues/6116), [PR #19919](https://github.com/dotnet/fsharp/pull/19919)) ### Added From c6d171029d5304f8a9499aeb14737a351298170c Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 15:19:11 +0200 Subject: [PATCH 7/9] Update AOT trim test8901 expectation for anon-record `{| ... |}` printing (#6116) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/AheadOfTime/Trimming/Program.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AheadOfTime/Trimming/Program.fs b/tests/AheadOfTime/Trimming/Program.fs index 6f5e806b099..2ab73bc9bb0 100644 --- a/tests/AheadOfTime/Trimming/Program.fs +++ b/tests/AheadOfTime/Trimming/Program.fs @@ -9093,7 +9093,7 @@ module PercentAPublicTests = let testPercentAMyAnonymousRecord () = let data = {| A = "Hello, World!"; B = 1.027m; C = 1028; D = 1.029 |} - test "test8901" (lazy (sprintf "%A" data).Replace("\n", ";")) """{ A = "Hello, World!"; B = 1.027M; C = 1028; D = 1.029 }""" + test "test8901" (lazy (sprintf "%A" data).Replace("\n", ";")) """{| A = "Hello, World!"; B = 1.027M; C = 1028; D = 1.029 |}""" let testDiscriminatedUnion () = test "test8902" (lazy (sprintf "%A" (IntNumber 10 )).Replace("\n", ";")) """IntNumber 10""" From 85744fac7b1f249aa47c6ae6f3f01a757057db72 Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 15:27:18 +0200 Subject: [PATCH 8/9] Bump expected trimmed DLL sizes for #6116 sformat.fs additions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/AheadOfTime/Trimming/check.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/AheadOfTime/Trimming/check.ps1 b/tests/AheadOfTime/Trimming/check.ps1 index 1695a3684f0..2abf9c9fb8a 100644 --- a/tests/AheadOfTime/Trimming/check.ps1 +++ b/tests/AheadOfTime/Trimming/check.ps1 @@ -63,10 +63,10 @@ function CheckTrim($root, $tfm, $outputfile, $expected_len, $callerLineNumber) { $allErrors = @() # Check net9.0 trimmed assemblies -$allErrors += CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 311808 -callerLineNumber 66 +$allErrors += CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 314880 -callerLineNumber 66 # Check net9.0 trimmed assemblies with static linked FSharpCore -$allErrors += CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9169408 -callerLineNumber 69 +$allErrors += CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9172992 -callerLineNumber 69 # Check net9.0 trimmed assemblies with F# metadata resources removed $allErrors += CheckTrim -root "FSharpMetadataResource_Trimming_Test" -tfm "net9.0" -outputfile "FSharpMetadataResource_Trimming_Test.dll" -expected_len 7609344 -callerLineNumber 72 From 74cabe7598cf39af0ade166077ac5f6baa2c178f Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 9 Jun 2026 15:53:59 +0200 Subject: [PATCH 9/9] Update FSharpSuite printing baselines for anon-record `{| ... |}` (#6116) Regenerate FSI printing baselines under tests/fsharp/core/printing/ so they reflect the new (correct) anon-record value printing introduced by PR #19919 (fix for issue #6116). Five baselines now show `= {| AnonRecordField2 = 11 |}` instead of `= { AnonRecordField2 = 11 }`; nominal-record value lines are unchanged. Also update tests/fsharp/core/anon/{lib.fs,test.fsx} assertions whose runtime sprintf `%A` expectations encoded the old anon-record rendering, including the struct anon record case whose ToString() now prefixes `struct {| ... |}`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/fsharp/core/anon/lib.fs | 4 ++-- tests/fsharp/core/anon/test.fsx | 6 +++--- tests/fsharp/core/printing/output.1000.stdout.bsl | 6 +++--- tests/fsharp/core/printing/output.200.stdout.bsl | 6 +++--- tests/fsharp/core/printing/output.multiemit.stdout.bsl | 6 +++--- tests/fsharp/core/printing/output.off.stdout.bsl | 2 +- tests/fsharp/core/printing/output.stdout.bsl | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/fsharp/core/anon/lib.fs b/tests/fsharp/core/anon/lib.fs index 271c8266b46..80fb262b44d 100644 --- a/tests/fsharp/core/anon/lib.fs +++ b/tests/fsharp/core/anon/lib.fs @@ -52,8 +52,8 @@ module KindB1 = check "coijoiwcnkwle1" {| a = 1 |} {| a = 1 |} check "coijoiwcnkwle2" {| a = 2 |} {| a = 2 |} - check "coijoiwcnkwle3" (sprintf "%A" {| X = 10 |}) "{ X = 10 }" - check "coijoiwcnkwle4" (sprintf "%A" {| X = 10; Y = 1 |}) "{ X = 10\n Y = 1 }" + check "coijoiwcnkwle3" (sprintf "%A" {| X = 10 |}) "{| X = 10 |}" + check "coijoiwcnkwle4" (sprintf "%A" {| X = 10; Y = 1 |}) "{| X = 10\n Y = 1 |}" check "clekoiew09" (f2 {| X = {| X = 10 |} |}) 10 check "cewkew0oijew" (f2 {| X = {| X = 20 |} |}) 20 diff --git a/tests/fsharp/core/anon/test.fsx b/tests/fsharp/core/anon/test.fsx index 6b065cdd7f0..2b0b9f7427c 100644 --- a/tests/fsharp/core/anon/test.fsx +++ b/tests/fsharp/core/anon/test.fsx @@ -25,13 +25,13 @@ module Test = let testAccess = (KindB1.data1.X, KindB1.data3.X) - check "coijoiwcnkwle2" (sprintf "%A" KindB1.data1) "{ X = 1 }" + check "coijoiwcnkwle2" (sprintf "%A" KindB1.data1) "{| X = 1 |}" module Tests2 = let testAccess = (KindB2.data1.X, KindB2.data3.X, KindB2.data3.Y) - check "coijoiwcnkwle3" (sprintf "%A" KindB2.data1) "{ X = 1 }" + check "coijoiwcnkwle3" (sprintf "%A" KindB2.data1) "{| X = 1 |}" let _ = (KindB2.data1 = KindB2.data1) @@ -49,7 +49,7 @@ module CrossAssemblyTest = check "vrknvio1" (SampleAPI.SampleFunction {| A=1; B = "abc" |}) 4 // note, this is creating an instance of an anonymous record from another assembly. check "vrknvio2" (SampleAPI.SampleFunctionAcceptingList [ {| A=1; B = "abc" |}; {| A=2; B = "def" |} ]) [4; 5] // note, this is creating an instance of an anonymous record from another assembly. check "vrknvio3" (let d = SampleAPI.SampleFunctionReturningAnonRecd() in d.A + d.B.Length) 4 - check "vrknvio4" (let d = SampleAPIStruct.SampleFunctionReturningAnonRecd() in d.ToString()) ("{ A = 1\n " + """B = "abc" }""") + check "vrknvio4" (let d = SampleAPIStruct.SampleFunctionReturningAnonRecd() in d.ToString()) ("struct {| A = 1\n " + """B = "abc" |}""") tests() module CrossAssemblyTestStruct = diff --git a/tests/fsharp/core/printing/output.1000.stdout.bsl b/tests/fsharp/core/printing/output.1000.stdout.bsl index c856eef8fc6..bf2d4d45814 100644 --- a/tests/fsharp/core/printing/output.1000.stdout.bsl +++ b/tests/fsharp/core/printing/output.1000.stdout.bsl @@ -2810,7 +2810,7 @@ val it: unit = () > {"AnonRecordField2":10} val it: unit = () -> val it: {| AnonRecordField2: int |} = { AnonRecordField2 = 11 } +> val it: {| AnonRecordField2: int |} = {| AnonRecordField2 = 11 |} module FSI_0326.Project.fsproj @@ -2837,10 +2837,10 @@ val test4a: string = "{"MutableField4":15}" > type R5 = {| AnonRecordField5: int |} val test5a: string = "{"AnonRecordField5":17}" -> val test5b: R5 = { AnonRecordField5 = 17 } +> val test5b: R5 = {| AnonRecordField5 = 17 |} > val test5c: string = "{"AnonRecordField5":18}" -> val test5d: R5 = { AnonRecordField5 = 18 } +> val test5d: R5 = {| AnonRecordField5 = 18 |} > > > diff --git a/tests/fsharp/core/printing/output.200.stdout.bsl b/tests/fsharp/core/printing/output.200.stdout.bsl index f631daf9b1e..20c5d9517f7 100644 --- a/tests/fsharp/core/printing/output.200.stdout.bsl +++ b/tests/fsharp/core/printing/output.200.stdout.bsl @@ -2055,7 +2055,7 @@ val it: unit = () > {"AnonRecordField2":10} val it: unit = () -> val it: {| AnonRecordField2: int |} = { AnonRecordField2 = 11 } +> val it: {| AnonRecordField2: int |} = {| AnonRecordField2 = 11 |} module FSI_0326.Project.fsproj @@ -2082,10 +2082,10 @@ val test4a: string = "{"MutableField4":15}" > type R5 = {| AnonRecordField5: int |} val test5a: string = "{"AnonRecordField5":17}" -> val test5b: R5 = { AnonRecordField5 = 17 } +> val test5b: R5 = {| AnonRecordField5 = 17 |} > val test5c: string = "{"AnonRecordField5":18}" -> val test5d: R5 = { AnonRecordField5 = 18 } +> val test5d: R5 = {| AnonRecordField5 = 18 |} > > > diff --git a/tests/fsharp/core/printing/output.multiemit.stdout.bsl b/tests/fsharp/core/printing/output.multiemit.stdout.bsl index 61e575a929c..7b0e7a67d83 100644 --- a/tests/fsharp/core/printing/output.multiemit.stdout.bsl +++ b/tests/fsharp/core/printing/output.multiemit.stdout.bsl @@ -6357,7 +6357,7 @@ val it: unit = () > {"AnonRecordField2":10} val it: unit = () -> val it: {| AnonRecordField2: int |} = { AnonRecordField2 = 11 } +> val it: {| AnonRecordField2: int |} = {| AnonRecordField2 = 11 |} module FSI_0325.Project.fsproj @@ -6384,10 +6384,10 @@ val test4a: string = "{"MutableField4":15}" > type R5 = {| AnonRecordField5: int |} val test5a: string = "{"AnonRecordField5":17}" -> val test5b: R5 = { AnonRecordField5 = 17 } +> val test5b: R5 = {| AnonRecordField5 = 17 |} > val test5c: string = "{"AnonRecordField5":18}" -> val test5d: R5 = { AnonRecordField5 = 18 } +> val test5d: R5 = {| AnonRecordField5 = 18 |} > > > diff --git a/tests/fsharp/core/printing/output.off.stdout.bsl b/tests/fsharp/core/printing/output.off.stdout.bsl index 034110b2168..ae3ab918b37 100644 --- a/tests/fsharp/core/printing/output.off.stdout.bsl +++ b/tests/fsharp/core/printing/output.off.stdout.bsl @@ -1824,7 +1824,7 @@ val it: unit > {"AnonRecordField2":10} val it: unit = () -> val it: {| AnonRecordField2: int |} = { AnonRecordField2 = 11 } +> val it: {| AnonRecordField2: int |} = {| AnonRecordField2 = 11 |} module FSI_0326.Project.fsproj diff --git a/tests/fsharp/core/printing/output.stdout.bsl b/tests/fsharp/core/printing/output.stdout.bsl index 61e575a929c..7b0e7a67d83 100644 --- a/tests/fsharp/core/printing/output.stdout.bsl +++ b/tests/fsharp/core/printing/output.stdout.bsl @@ -6357,7 +6357,7 @@ val it: unit = () > {"AnonRecordField2":10} val it: unit = () -> val it: {| AnonRecordField2: int |} = { AnonRecordField2 = 11 } +> val it: {| AnonRecordField2: int |} = {| AnonRecordField2 = 11 |} module FSI_0325.Project.fsproj @@ -6384,10 +6384,10 @@ val test4a: string = "{"MutableField4":15}" > type R5 = {| AnonRecordField5: int |} val test5a: string = "{"AnonRecordField5":17}" -> val test5b: R5 = { AnonRecordField5 = 17 } +> val test5b: R5 = {| AnonRecordField5 = 17 |} > val test5c: string = "{"AnonRecordField5":18}" -> val test5d: R5 = { AnonRecordField5 = 18 } +> val test5d: R5 = {| AnonRecordField5 = 18 |} > > >