Skip to content

Fix FSI pretty printing for anonymous records#19919

Open
T-Gro wants to merge 9 commits into
mainfrom
fix/issue-6116
Open

Fix FSI pretty printing for anonymous records#19919
T-Gro wants to merge 9 commits into
mainfrom
fix/issue-6116

Conversation

@T-Gro

@T-Gro T-Gro commented Jun 9, 2026

Copy link
Copy Markdown
Member

Fixes #6116

FSI printed anonymous records with { ... } (nominal record syntax) instead
of {| ... |}. Now the printer detects anonymous record types and uses the
correct delimiters, plus struct {| ... |} for struct anonymous records.

// before
{ Name = "Alice"; Age = 30 }

// after
{| Name = "Alice"
   Age = 30 |}

Copilot and others added 5 commits June 9, 2026 08:14
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…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>
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

❗ Release notes required

You can open this PR in browser to add release notes: open in github.dev


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/11.0.100.md

Copilot and others added 2 commits June 9, 2026 15:19
…ting (#6116)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added the AI-Tooling-Check-Bypassed Tooling check: non-fork PR, not diff-analyzed label Jun 9, 2026
)

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI-Tooling-Check-Bypassed Tooling check: non-fork PR, not diff-analyzed

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

FSI pretty print of values shows the same text for records and anonymous records

2 participants