Skip to content

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

Draft
github-actions[bot] wants to merge 1 commit intomainfrom
repo-assist/fix-issue-2529-record-copy-nested-parens-64eba4aee41da49f
Draft

[Repo Assist] Fix record copy expression indentation when nested in parentheses#3297
github-actions[bot] wants to merge 1 commit intomainfrom
repo-assist/fix-issue-2529-record-copy-nested-parens-64eba4aee41da49f

Conversation

@github-actions
Copy link
Contributor

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

Closes #2529

Root Cause

When formatting a multiline record copy expression (e.g. { r with Z = 1; X = "value" }) that is nested inside parentheses, the genMultilineRecordCopyExpr function could produce F# offside errors.

The issue is in how indentation is computed for the record fields:

  1. atCurrentColumnIndent (genExpr copyExpr) writes the copy-expression identifier (r) at the current column C, temporarily setting Indent = C
  2. After that call completes, Indent is restored to the outer binding body level (e.g. 4)
  3. indent (IndentBy IndentSize) then computes the field indent as 4 + 4 = 8
  4. When nested parens push r to column 8 as well, Z = 1 lands at the same column as roffside error

Example before:

let b =
    (({ r with
            Z = 1        // <- same column as 'r' above! F# rejects this.
            X = "longstring value here"
    }))

Fix

Capture the column where the copy-expression identifier will be written before calling atCurrentColumnIndent. After the normal indent call, if the resulting Indent would be the copy-expression column, bump it to copyExprColumn + IndentSize. Use RestoreIndent (instead of unindent/unindent) to cleanly restore the original indent level.

Example after:

let b =
    (({ r with
            Z = 1        // <- 4 columns past 'r' ✓
            X = "longstring value here"
    }))

The fix is backward-compatible: for the common case where the copy expression is not deeply nested, Indent + IndentSize > copyExprColumn is already true and no adjustment is made.

Trade-offs

  • Minimal change: only genMultilineRecordCopyExpr is modified
  • Replaces onlyIf addAdditionalIndent unindent +> unindent with a single RestoreIndent oldIndent — equivalent in the common case, but correct when the indent was manually bumped

Test Status

  • Build: ✅ succeeded
  • Tests: ✅ 2739 passed, 7 skipped, 0 failed (added 1 new regression test)

New regression test added in AlignedMultilineBracketStyleTests.fs: record copy expression nested in parentheses should not produce offside errors

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@346204513ecfa08b81566450d7d599556807389f

)

Record copy expressions nested inside parentheses could produce F# offside
errors after formatting. For example:

    let b = (({ r with Z = 1; X = "longstring value here" }))

would format as:

    let b =
        (({ r with
                Z = 1        <- fields at same column as 'r' -> offside error!
                X = "longstring value here"
        }))

Root cause: genMultilineRecordCopyExpr uses atCurrentColumnIndent to write
the copy-expression identifier, which saves/restores the indentation context.
The subsequent indent call then uses the restored (outer binding body) indent
level. When nested parens push the identifier to the same column as
outer_indent + IndentSize, the fields end up at the same column as the
identifier, violating F# indentation rules.

Fix: capture the copy-expression column before writing it, then after the
normal indent computation, ensure the resulting field indent is strictly
greater than the copy-expression column. Use explicit RestoreIndent to cleanly
restore the old indent level afterward.

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

0 participants