Impact
Running the formatter twice on the same file produces two different outputs for statements of the shape await (call(func() -> void: body()).chain("long argument")) when the line exceeds max-line-length. The first pass only expands the lambda; the second pass additionally wraps the outer parenthesized group and re-indents the lambda body one level deeper. Output converges from the second pass on.
Minimal repro
repro.gd (the statement line exceeds the default limit):
extends Node
func f() -> void:
await (check(func() -> void: do_work()).report("some quite long message that pushes this line well past the limit"))
gdscript-formatter repro.gd
gdscript-formatter --check repro.gd # exit 1 — the file it just wrote is "not formatted"
gdscript-formatter repro.gd # changes the file again
Actual output
After pass 1:
func f() -> void:
await (check(func() -> void:
do_work()).report("some quite long message that pushes this line well past the limit"))
After pass 2 (differs from pass 1 — outer group and call arguments now wrapped, lambda body indented one level deeper):
func f() -> void:
await (
check(func() -> void:
do_work()).report(
"some quite long message that pushes this line well past the limit"
)
)
Pass 3 output equals pass 2 (converged).
Expected
Pass 1 should directly produce the fixpoint (whatever shape that is) — format followed by --check on the same file should always exit 0.
Boundary (verified individually on 0.22.0)
Idempotent:
- The same statement without the outer parentheses, or short enough to fit the limit
call(func() -> void: body()).chain("...") without await (...) wrapping (converges in one pass)
Not idempotent (two passes needed):
- Overlong
await ( call(<single-line lambda>).chain(...) ) statements — the single-line lambda's expansion in pass 1 seems to happen after the wrapping decisions, so the extra wrapping that the now-taller statement needs is only applied on the next run
Impact
Running the formatter twice on the same file produces two different outputs for statements of the shape
await (call(func() -> void: body()).chain("long argument"))when the line exceedsmax-line-length. The first pass only expands the lambda; the second pass additionally wraps the outer parenthesized group and re-indents the lambda body one level deeper. Output converges from the second pass on.Minimal repro
repro.gd(the statement line exceeds the default limit):Actual output
After pass 1:
After pass 2 (differs from pass 1 — outer group and call arguments now wrapped, lambda body indented one level deeper):
Pass 3 output equals pass 2 (converged).
Expected
Pass 1 should directly produce the fixpoint (whatever shape that is) —
formatfollowed by--checkon the same file should always exit 0.Boundary (verified individually on 0.22.0)
Idempotent:
call(func() -> void: body()).chain("...")withoutawait (...)wrapping (converges in one pass)Not idempotent (two passes needed):
await ( call(<single-line lambda>).chain(...) )statements — the single-line lambda's expansion in pass 1 seems to happen after the wrapping decisions, so the extra wrapping that the now-taller statement needs is only applied on the next run