Skip to content

[rust-compiler] Fix off-by-one in SWC source-location conversion#36501

Closed
poteto wants to merge 1 commit into
facebook:pr-36173from
poteto:rust-compiler-swc-loc-zero-based
Closed

[rust-compiler] Fix off-by-one in SWC source-location conversion#36501
poteto wants to merge 1 commit into
facebook:pr-36173from
poteto:rust-compiler-swc-loc-zero-based

Conversation

@poteto
Copy link
Copy Markdown
Collaborator

@poteto poteto commented May 21, 2026

What

position() in the SWC convert_ast was binary-searching SWC's 1-based BytePos against the 0-based line_offsets table, producing loc.{start,end}.{line,column,index} values that were off by 1 in events. When the referenced byte happened to fall just before a \n, the result flipped to "next line, column 0", e.g. TS reports line: 3, column: 18 and SWC reported line: 4, column: 0 for the same source position.

Fix

Shift the offset down by 1 (saturating, to keep DUMMY spans at 0) before the line lookup. BaseNode.start/end keeps the SWC-native 1-based value because convert_scope keys its node_to_scope map on span.lo.0 and the HIR builder looks it up via base.start; changing those would require updating both convert_scope and the reverse converter together. Doing the focused fix on loc clears the bulk of the divergence with minimal blast radius.

Also drop the e2e harness's oneBasedColumns = variant === 'swc' workaround that was attempting to compensate post-hoc by subtracting 1 from column/index but couldn't handle the cases where the off-by-one had pushed the position onto a different line.

Test plan

Variant Before After Delta
swc 1682/1795 (113 failures) 1742/1795 (53 failures) +60 fixed
babel 1788/1795 1788/1795 unchanged
oxc 1702/1795 1702/1795 unchanged
  • cargo test --workspace: 56 passed, 0 failed (unchanged)
  • The dominant remaining SWC cluster (10 source-location diffs) appears to be different bugs, not residue of this one.

SWC's BytePos is 1-based (BytePos(0) is the DUMMY/synthetic sentinel)
while the Babel AST that the rest of the compiler consumes uses
0-based offsets in loc.{start,end}.{line,column,index}. `position()`
in the SWC convert_ast was binary-searching the 1-based offset
against the 0-based line_offsets table, producing line/column/index
values that were off by 1, and that flipped to "next line, column 0"
when the referenced byte happened to be the byte right before a `\n`.

Shift the offset down by 1 before the line lookup. BaseNode.start/end
keeps the SWC-native 1-based value because the SWC scope collector
keys its node_to_scope map on span.lo.0 and the HIR builder looks it
up via base.start.

Also drop the e2e harness's `oneBasedColumns = variant === 'swc'`
workaround that was masking part of this divergence.

Test plan:
- bash compiler/scripts/test-e2e.sh --variant swc:
    Before: Total 1682/1795 (113 failures)
    After:  Total 1742/1795 (53 failures, 60 fixed)
- bash compiler/scripts/test-e2e.sh --variant babel: 1788/1795 (unchanged)
- bash compiler/scripts/test-e2e.sh --variant oxc:   1702/1795 (unchanged)
- cargo test --workspace: 56 passed, 0 failed (unchanged)
@meta-cla meta-cla Bot added the CLA Signed label May 21, 2026
@github-actions github-actions Bot added the React Core Team Opened by a member of the React Core Team label May 21, 2026
@poteto
Copy link
Copy Markdown
Collaborator Author

poteto commented May 21, 2026

Superseded by #36502 (and the rest of the SWC parity stack, #36502#36511). Closing in favor of the split-up stack.

@poteto poteto closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant