Semantic Diff

#9166 Give template segments the location of their text

2 commits

0800cb42b8f279c41e2edc57c67763628ea0bdb4..pr-9166

fa0d7d430 · cknitt + Claude · Nov 01, 2026, 11:14 UTC

Give template segments the location of their text

Why

A template segment's location started at the delimiter before it (a backquote or }) and ended before the one after it (${ or a backquote), so it was neither the text nor the text with its delimiters. The old shape is what made the v0 bridge lose a character of a template's location (#9164). Segments now cover their text only.

modifiedAST template segment locations

let y = `a${b}c`
text
Before
After
expression 8..16 segments "a" 8..10, "c" 13..15covering `a${b}c` `a }cexpression 8..16 segments "a" 9..10, "c" 14..15covering `a${b}c` a c

modifiedDiagnostic invalid escape in a template

let invalid = `\unicode`
diagnostic
Before
After
Syntax error!Syntax error!A.res:1:15-23A.res:1:16-23

Review

  • What else reads segment locations? Invalid escape errors, now pointing at the text; Ast_raw.payload_loc, which now widens a %raw template by one character on each side; and the v0 bridge, which keeps each segment's location as it is.
506cb2579 · cknitt + Claude · Nov 01, 2026, 08:57 UTC

Keep the location of templates without interpolations through ast0

Why

On the v0 wire, a template without interpolations was one string constant at its segment's location, which ends before the closing backquote, so the template lost one character of its location after a PPX round trip. The constant now takes the template's location, and the segment's location is derived from it on the way back (#9164).

modifiedAST template after the v0 round trip

let z = `template`
text
Before
After
parsed: expression [1,0+8]..[1,0+18]parsed: expression [1,0+8]..[1,0+18]after the round trip: expression [1,0+8]..[1,0+17]after the round trip: expression [1,0+8]..[1,0+18]