Skip to content

v: refactor $var to ${var} across entire repository - #26494

Merged
spytheman merged 4 commits into
vlang:masterfrom
revosw:refactor-string-interpolation
Feb 1, 2026
Merged

spytheman merged 4 commits into
vlang:masterfrom
revosw:refactor-string-interpolation

Conversation

@revosw

@revosw revosw commented Feb 1, 2026 •

Copy link
Copy Markdown
Contributor

String interpolation has two supported variants as of today. $var and ${var}, with ${var} being preferred.

vfmt automatically converts $var to ${var}, but only for code that runs. Comments, .vsh files and test artifacts such as .vv, .out and such are unaffected. Refactoring all occurrences to the new format is a step in entirely removing the interpolation support for $var.

scanner.v has not been altered, a follow-up commit that actually removes support for $var can do the final work in rephrasing comments and such.

Other notes:

str.v:348 | Need to rephrase comment regarding interpolation
syntax.v_:306 | Not sure what effect changing $literal to ${literal} has here, didn't touch

String interpolation has two supported variants as of today. '$var' and '${var}', with '${var}' being preferred.

Refactoring all occurrences to the new format is a step in entirely removing the interpolation support for '$var'.

scanner.v has not been altered, a follow-up commit that actually removes support for $var can do the final work in rephrasing comments and such.
@revosw

revosw commented Feb 1, 2026

Copy link
Copy Markdown
Contributor Author

If I understand the vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv failure correctly, I should change array := ... from:

fn main() {
  array := ['a', 'b', 'c']

  print_1(array[0])

  print_1(...array)
  print_2(...array)
  print_3(...array)

  print_1(...array[1..2])
  print_2(...array[1..])

  println('================ V panic ================')
  print_4(...array)
}

To:

fn main() {
  array := ['\${a}', '\${b}', '\${c}']

  print_1(array[0])

  print_1(...array)
  print_2(...array)
  print_3(...array)

  print_1(...array[1..2])
  print_2(...array[1..])

  println('================ V panic ================')
  print_4(...array)
}

@revosw

revosw commented Feb 1, 2026

Copy link
Copy Markdown
Contributor Author

There is also other output that is misaligned, for example the ~~~~ in this check

Error: vlib/v/scanner/tests/undefined_ident_in_string_literal_err.vv:2:16: error: expression does not return a value
    1 | fn abc() string {
    2 |     return 'abc ${type}'
      |                   ~~~~
    3 | }
    4 |
============

diff: 
@@ -1,13 +1,13 @@
Error: -vlib/v/scanner/tests/undefined_ident_in_string_literal_err.vv:2:15: error: undefined ident: `type`
-    1 | fn abc() string {
-    2 |     return 'abc ${type}'
-      |                  ~~~~
-    3 | }
-    4 |
Error: -vlib/v/scanner/tests/undefined_ident_in_string_literal_err.vv:2:15: error: expression does not return a value
-    1 | fn abc() string {
-    2 |     return 'abc ${type}'
-      |                  ~~~~
Error: +vlib/v/scanner/tests/undefined_ident_in_string_literal_err.vv:2:16: error: undefined ident: `type`
+    1 | fn abc() string {
+    2 |     return 'abc ${type}'
+      |                   ~~~~
+    3 | }
+    4 |
Error: +vlib/v/scanner/tests/undefined_ident_in_string_literal_err.vv:2:16: error: expression does not return a value
+    1 | fn abc() string {
+    2 |     return 'abc ${type}'
+      |                   ~~~~
    3 | }
    4 |

I should run v test-all locally and fix the ones that are obvious from my changes

@JalonSolov

Copy link
Copy Markdown
Collaborator

If I understand the vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv failure correctly, I should change array := ... from:

fn main() {
  array := ['a', 'b', 'c']

  print_1(array[0])

  print_1(...array)
  print_2(...array)
  print_3(...array)

  print_1(...array[1..2])
  print_2(...array[1..])

  println('================ V panic ================')
  print_4(...array)
}

To:

fn main() {
  array := ['\${a}', '\${b}', '\${c}']

  print_1(array[0])

  print_1(...array)
  print_2(...array)
  print_3(...array)

  print_1(...array[1..2])
  print_2(...array[1..])

  println('================ V panic ================')
  print_4(...array)
}

No, this is incorrect. There are no variables by those names, and no $ in front of them in the current strings, so that bit should not be modified at all.

@revosw

revosw commented Feb 1, 2026

Copy link
Copy Markdown
Contributor Author

I'll consolidate the errors in this one message.

  • vlib\v\checker\tests\prefix_err.out

I have mistakenly changed the error message from error: cannot take the address of '$b' to error: cannot take the address of '${b}'.

vlib/v/checker/tests/prefix_err.vv:11:6: error: cannot take the address of '${b}'
    9 | _ := &10
   10 | _ := &'Hi'
   11 | _ := &'${b}'
      |      ^
   12 | _ := &`c`
   13 | _ := &1.2

My guess is that it's because ast.StringInterLiteral uses a str() that outputs the contents of the string interpolation, not including ${ and }. But I haven't looked deep into it.

fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {

	// ...

	if node.op == .amp && (!right_is_ptr || (right_is_ptr && expr is ast.CallExpr)) {
		if expr in [ast.BoolLiteral, ast.CallExpr, ast.CharLiteral, ast.FloatLiteral, ast.IntegerLiteral,
			ast.InfixExpr, ast.StringLiteral, ast.StringInterLiteral] {
			c.error('cannot take the address of ${expr}', node.pos)
		}

		// ...
	}
}
  • vlib/v/slow_tests/inout/comptime_smartcast_variant.vv
    Exactly the same behavior as prefix_err.out. The checker outputs the interpolation as $var instead of ${var}

I was going to write out all of the tests, but I would just be repeating myself. Should I change all my .out files to simply contain $var, or is it desirable that the string representation of a string interpolation is changed to the ${var} form?

@JalonSolov

Copy link
Copy Markdown
Collaborator

${var} is the correct form in all string interpolation cases. If you want to print the actual characters, \${var} should work... if it doesn't, it's a bug.

Removes `needs_braces` from get_fspec_braces and renames method to `get_fspec`

In an effort to completely deprecate interpolation without curly braces, the .str() method of a string literal will now always output with braces, for example `${name}` instead of `$name`
@revosw

revosw commented Feb 1, 2026

Copy link
Copy Markdown
Contributor Author

I am very pleased to say that I consider this pull request ready for proper review after CI has finished.

In the commit "ast: always output string literals with braces", I took the liberty to refactor get_fspec_braces (now called get_fspec) and their call sites to completely remove needs_braces and the conditional branching related to it. Now it always output braces.

@spytheman spytheman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work.
Thank you @revosw πŸ™‡πŸ» for the patience and perseverance .

@spytheman
spytheman merged commit 2332ecf into vlang:master Feb 1, 2026
101 of 102 checks passed
@revosw
revosw deleted the refactor-string-interpolation branch February 7, 2026 10:08
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.

3 participants