Skip to content

[Repo Assist] Fix record copy expression indentation when nested in parentheses#3330

Closed
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/fix-issue-2529-record-copy-v2-20260403-ab3d18174e91f4d1
Closed

[Repo Assist] Fix record copy expression indentation when nested in parentheses#3330
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/fix-issue-2529-record-copy-v2-20260403-ab3d18174e91f4d1

Conversation

@github-actions

@github-actions github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

🤖 This PR was created by Repo Assist, an automated AI assistant.

Closes #2529

Root Cause

When a record copy expression (e.g. { r with Z = 1 }) was nested inside parentheses like:

let b =
    (({ r with
            Z = 1
            X = "value" }))
```

the formatter produced fields indented at the same column as `r`, violating F#'s offside rule:

```
error FS0010: Unexpected keyword 'with' or incomplete expression
```

In `genMultilineRecordCopyExpr`, `atCurrentColumnIndent` temporarily uses the copy expression's column (e.g. 8) as a "current column" anchor, then restores the outer indent (4) after writing the expression. When `indent` then runs, it adds `IndentSize` (4) to that restored outer indent → 8, which is the **same column** as `r`. The F# offside rule requires fields to be **strictly** to the right, so the formatted output would not compile.

## Fix

Before calling `atCurrentColumnIndent`, capture both `ctx.Column` (the copy expression start column) and `ctx.WriterModel.Indent` (the previous indent level). After `indent` runs, if the resulting indent level is at or below the copy expression column, bump it to `copyExprStartColumn + IndentSize`. At the end, use `RestoreIndent oldIndent` to correctly restore the saved level regardless of the bump.

## Trade-offs

- The fix is surgical only `genMultilineRecordCopyExpr` is changed, and only when the nested-paren pathological case is detected (`Indent <= copyExprStartColumn`).
- In normal non-nested cases the condition is false and no bump occurs, so there is no change in existing formatting behaviour.
- Full test suite (2770 tests) passes.

## Test Status

```
Passed!  - Failed: 0, Passed: 2770, Skipped: 7, Total: 2777

A regression test was added to AlignedMultilineBracketStyleTests.fs covering the exact scenario from issue #2529.

Note: this supersedes the earlier draft PR #3297 which targeted an older base and is now 31 commits behind main.

Generated by 🌈 Repo Assist, see workflow run. Learn more.

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@4ea8c81959909f40373e2a5c2b7fdb54ea19e0a5

When a record copy expression (e.g. `{ r with Z = 1 }`) was nested inside
parentheses, the fields were indented to the same column as the copy
expression variable `r`, violating F#'s offside rule and causing a
compiler error.

Root cause: genMultilineRecordCopyExpr used atCurrentColumnIndent to
capture r's column (e.g. 8), then indent() added IndentSize (4) to the
restored outer indent (4) = 8, same as r's column.

Fix: detect when the post-indent level is at or below the copy expression
column and bump it by IndentSize so fields are always strictly to the
right of the copy expression.

Fixes #2529

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Indentation warnings in record expression

1 participant