Summary
Maintain eliminate uses syn to parse and prettyplease to reprint the entire file whenever any single-use binding is inlined. This means even one eliminated let causes the entire file to be reformatted — removing inline // comments, collapsing blank lines, restructuring use imports, and changing code layout far beyond the site of the inlined binding.
Reproduction
~/Developer/Application/CodeEditorLand/Land/Target/release/Maintain eliminate \
--path ./Source/Air \
--verbose
Run against Element/Mountain/Source/Air, the diff shows:
- All section-separator comments (e.g.
// --- Authentication Operations ---) removed
- All blank lines between methods and blocks collapsed or dropped
- Multi-line
use declarations reformatted into a single line
pub mod declarations (e.g. pub mod AirMetrics, pub mod AirStatus, etc.) removed from the output
- Doc-comment blocks on structs and constants stripped
- Structural labels like
// Address of the Air daemon, // Default gRPC server address gone
let intermediate variables collapsed into deeply nested method chains, making the code harder to follow
Root Cause
In Source/Eliminate/Transform/mod.rs, Run() unconditionally calls prettyplease::unparse(&Ast) on the entire syn::File whenever AnyChanged == true:
// Transform/mod.rs
if !AnyChanged {
return Ok(None);
}
Ok(Some(prettyplease::unparse(&Ast)))
syn does not preserve non-doc // comments, blank lines, or original whitespace structure — these are not represented in the AST. prettyplease then regenerates canonical formatting with no knowledge of the original layout. The result is that a single inlined binding triggers a total rewrite of every file it touches.
Desired Behaviour (aggressive mode)
We prefer aggressive inlining — single-use variables should be eliminated without hesitation — but the output should preserve the original file's:
- Inline
// comments and section-separator comments
- Blank lines used for visual grouping between methods, sections, and logical blocks
- Multi-line
use and pub mod formatting
- Doc-comment blocks on items not being eliminated
Suggested Fixes
Option A — Preserve original whitespace/comment regions via text-level patching
Instead of reprinting the whole file, identify the line ranges of each inlined let statement in the original source and splice only those lines out, substituting the inlined expression at the usage site using a text-level replacement. This preserves all surrounding lines verbatim.
Requires tracking byte/line spans from syn's Span information through the substitution phase.
Option B — Use a comment-preserving Rust formatter
Switch from prettyplease (which drops comments) to a formatter that round-trips comments — for example rustfmt directly via rustfmt_nightly API or rust-analyzer's formatter, which both preserve comments. Then the full-file reprint would at least keep comments intact.
Option C — Split into two passes: eliminate first, normalize separately
Only write back the minimal diff (just the affected let + usage lines) when running in default mode. Provide a separate --normalize flag (or a second command) for users who explicitly want full-file canonical formatting. This way eliminate is safe to run on code with hand-crafted layout and comments.
Option D — Pre/post comment stitching
Before calling prettyplease::unparse, extract all // comment lines and their surrounding blank lines from the original source indexed by line number. After reprinting, attempt to re-insert them at matching structural positions. This is lossy for comments that were inline on the same line as code, but preserves section-separator blocks.
Impact
- Files that have been through
eliminate no longer compile in some cases (see separate issue for E0382 borrow-after-move).
- All formatting conventions, section structure, and documentation in files under
Source/Air have been erased.
- Running
eliminate a second time re-triggers all files as "changed" if the formatter output differs from the stored version, making it non-idempotent at the project level even though individual transforms are idempotent.
Context
- Invocation:
Maintain eliminate --path ./Source/Air --verbose
- Affected files:
Source/Air/AirClient.rs, Source/Air/AirServiceProvider.rs (and likely all .rs files under Source/Air)
- Branch:
Current
Eliminate::Definition::Options::InlineComments defaults to false — doc-commented bindings are excluded from inlining — but this flag does not protect surrounding comments or blank lines from being erased during the reprint step.
Summary
Maintain eliminateusessynto parse andprettypleaseto reprint the entire file whenever any single-use binding is inlined. This means even one eliminatedletcauses the entire file to be reformatted — removing inline//comments, collapsing blank lines, restructuringuseimports, and changing code layout far beyond the site of the inlined binding.Reproduction
~/Developer/Application/CodeEditorLand/Land/Target/release/Maintain eliminate \ --path ./Source/Air \ --verboseRun against
Element/Mountain/Source/Air, the diff shows:// --- Authentication Operations ---) removedusedeclarations reformatted into a single linepub moddeclarations (e.g.pub mod AirMetrics,pub mod AirStatus, etc.) removed from the output// Address of the Air daemon,// Default gRPC server addressgoneletintermediate variables collapsed into deeply nested method chains, making the code harder to followRoot Cause
In
Source/Eliminate/Transform/mod.rs,Run()unconditionally callsprettyplease::unparse(&Ast)on the entiresyn::FilewheneverAnyChanged == true:syndoes not preserve non-doc//comments, blank lines, or original whitespace structure — these are not represented in the AST.prettypleasethen regenerates canonical formatting with no knowledge of the original layout. The result is that a single inlined binding triggers a total rewrite of every file it touches.Desired Behaviour (aggressive mode)
We prefer aggressive inlining — single-use variables should be eliminated without hesitation — but the output should preserve the original file's:
//comments and section-separator commentsuseandpub modformattingSuggested Fixes
Option A — Preserve original whitespace/comment regions via text-level patching
Instead of reprinting the whole file, identify the line ranges of each inlined
letstatement in the original source and splice only those lines out, substituting the inlined expression at the usage site using a text-level replacement. This preserves all surrounding lines verbatim.Requires tracking byte/line spans from
syn'sSpaninformation through the substitution phase.Option B — Use a comment-preserving Rust formatter
Switch from
prettyplease(which drops comments) to a formatter that round-trips comments — for examplerustfmtdirectly viarustfmt_nightlyAPI orrust-analyzer's formatter, which both preserve comments. Then the full-file reprint would at least keep comments intact.Option C — Split into two passes: eliminate first, normalize separately
Only write back the minimal diff (just the affected
let+ usage lines) when running in default mode. Provide a separate--normalizeflag (or a second command) for users who explicitly want full-file canonical formatting. This wayeliminateis safe to run on code with hand-crafted layout and comments.Option D — Pre/post comment stitching
Before calling
prettyplease::unparse, extract all//comment lines and their surrounding blank lines from the original source indexed by line number. After reprinting, attempt to re-insert them at matching structural positions. This is lossy for comments that were inline on the same line as code, but preserves section-separator blocks.Impact
eliminateno longer compile in some cases (see separate issue forE0382borrow-after-move).Source/Airhave been erased.eliminatea second time re-triggers all files as "changed" if the formatter output differs from the stored version, making it non-idempotent at the project level even though individual transforms are idempotent.Context
Maintain eliminate --path ./Source/Air --verboseSource/Air/AirClient.rs,Source/Air/AirServiceProvider.rs(and likely all.rsfiles underSource/Air)CurrentEliminate::Definition::Options::InlineCommentsdefaults tofalse— doc-commented bindings are excluded from inlining — but this flag does not protect surrounding comments or blank lines from being erased during the reprint step.