Skip to content

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

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

v: refactor $var to ${var} across entire repository#26494
spytheman merged 4 commits intovlang:masterfrom
revosw:refactor-string-interpolation

Conversation

@revosw
Copy link
Copy Markdown
Contributor

@revosw revosw commented Feb 1, 2026

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
Copy link
Copy Markdown
Contributor Author

revosw commented Feb 1, 2026

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
Copy link
Copy Markdown
Contributor Author

revosw commented Feb 1, 2026

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
Copy link
Copy Markdown
Contributor Author

revosw commented Feb 1, 2026

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
Copy link
Copy Markdown
Contributor Author

revosw commented Feb 1, 2026

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.

Copy link
Copy Markdown
Contributor

@spytheman spytheman left a comment

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