Skip to content

transform: keep escaped ${ literal in interpolated strings - #28942

Merged
medvednikov merged 1 commit into
masterfrom
fix-escaped-dollar-after-interp
Sep 24, 2026
Merged

medvednikov merged 1 commit into
masterfrom
fix-escaped-dollar-after-interp

Conversation

@medvednikov

Copy link
Copy Markdown
Member

Problem

v ~/.vmodules/ui2/ide fails in C:

src.c: In function 'companion_main_source':
error: 'err' undeclared (first use in this function)
error: 'event' undeclared (first use in this function)

companion_main_source builds V source text with a string like
"... ${vml_escape(vml_name)}: \${err}') ...". The transform re-parsed the text of every
string literal inside a string interpolation as ${...} code. The parser has already
unescaped that text, so an escaped \${name} was expanded as a real interpolation.

Undeclared names fail in C. Declared names are silently substituted:

x := 'X'
println('${x} \${x}')             // printed `X X`, expected `X ${x}`
println('${x} \x24{x}')           // printed `X X`
println('${id('\${x}')}')         // printed `X`
println('${r'${x}'}')             // printed `X`
println('${tags.map('--\${x}')}') // printed `--X`

A string literal on its own ('\${x}') was fine. The bug needed a real interpolation in the
same string, or the literal nested inside one.

Fix

The re-parse was a workaround from before the scanner split nested interpolations itself
(#28331). A string literal the parser produces can no longer contain a real interpolation, so
transform_expr now passes string literals through unchanged. The recovery helpers this
leaves unused are removed, along with the in_string_interp_part flag. The ORM path still
uses simple_nested_string_interpolation for SQL tokens and is unchanged.

#28416 fixed the it case of this same bug on its own ('--\${it}' inside a map). That
test still passes.

Still open: transform_nested_if_string_interp_node / ..._match_... (and the matching
helper in if.v) apply the same kind of text heuristic to a 5-part interpolation, so
'\${if ok { ${a} } else { ${b} }}' still prints A. That needs an escaped \${if or
\${match followed by branch-shaped real interpolations. It is left out to keep this
change focused.

Tests

  • New vlib/v/tests/builtin_strings_and_interpolation/string_interpolation_escaped_dollar_test.v:
    escaped \${, \x24{, \044{, raw literals and escaped text inside interpolation
    expressions stay literal, and real nested interpolation still expands. Fails on master:
    C error for the undeclared-name case, assertion failures (X X vs X ${x}) without it.
  • v test vlib/v/tests/builtin_strings_and_interpolation/: 51/51 pass.
  • vlib/v/compiler_tests/nested_escaped_map_it_interp_test.v: passes.
  • ui2/ide now builds.

The transform re-parsed the text of every string literal inside a string
interpolation as `${...}` code. The parser has already unescaped that text,
so an escaped `\${name}` next to a real interpolation became a nested
interpolation: undeclared names failed in C (`'err' undeclared`, seen in
ui2/ide), and declared ones were silently substituted
(`'${x} \${x}'` printed `X X`). `\x24{`, `\044{` and raw literals inside an
interpolation hit the same path.

The re-parse was a workaround from before the scanner split nested
interpolations itself (#28331). A string literal the parser produces can no
longer hold a real interpolation, so pass string literals through unchanged
and drop the now-unused recovery helpers.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-24T16:00:31.109875Z bf5542f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@medvednikov
medvednikov merged commit cc87329 into master Sep 24, 2026
3 of 105 checks passed
@JalonSolov
JalonSolov deleted the fix-escaped-dollar-after-interp branch September 24, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant