This needs 2 files
File 1
# Name: test_format
import strformat
proc fails*(a: static[int]) =
echo &"formatted {a:2}"
proc fails2*[N: static[int]](a: int) =
echo &"formatted {a:2}"
proc works*(a: int) =
echo &"formatted {a:2}"
proc fails0*(a: int or uint) =
echo &"formatted {a:2}"
File 2
import test_format
works(5)
fails0(6)
fails(7)
fails2[0](8)
lib/pure/strformat.nim(276, 5) Error: undeclared identifier: 'format'
It seems like within a generic or static proc the compiler tries to resolve the identifier 'format' earlier than expected as format is declared after the macros that calls it here on line 489.
This seems related to https://github.com/nim-lang/Nim/issues/6387 (Generics proc + macros: identifier resolution happens before macro)
I suspect it's related to #5053 as well.
strformat doesn't work in templates too:
import strformat
template formatMsg(s: string): string =
&"test {s}"
echo formatMsg("x")
I have observed/reported this issue for other string interpolations before (my own outdated and nimboost). In these cases the underlying issue was the behavior of parseExpr. I had opened this issue to discuss if this can be fixed, but it turned out to be unsolvable.
We have a plan how to fix it. Templates expecting untyped params will be expanded earlier while the body of another template or generic is being read. Thus, the interpolation will produce AST nodes that will bind properly to the template parameters.
ping on this issue as it causes non-ideal bug-fixing workarounds like https://github.com/nim-lang/Nim/pull/9417 /cc @zah
I spent some time fixing/chaning this part of the language and it's not trivial, some other complex tests fail then...
@krux02 In general, could you write a quick comment when you close an issue like that? When I saw that this issue was closed I spend an hour trying to figure out why I still cannot get strformat to work in a template (I was going over the changes in the PR to see how they relate to the discussion here. Only when someone else posted that it is still not working I realized that it isn't a problem on my end). Since it still doesn't work, the issue should either stay open or say "won't fix" to avoid confusion. In any case, I like your workaround, reposting it here for other users:
template t(s): untyped =
block:
let x {.inject.} = s
&"test {x}"
This issue is fixed. The example from this issue has been added to the test case. Your problem is an entirely different problem. By now that example has been added to the documentation of strformat including an explanation why it can't work. It is a structural problem that can't simply be "fixed". In other languages that support string interpolation this problem does not occur because these other languages don't have nim like templates.
strformat doesn't work properly inside generics and templates_ and that is literally not fixed. Let's remove the "and template" and track the remaining issue in #10977 ?
This hasn't really been fixed for generics. The test case in git only works because the main test file tstrformat.nim imports strformat. If you run the original test case where the import strformat is not present, it still fails.
@jcosborn I just tested it again on development branch of Nim. The example from the issue works.
The test case in git only works because the main test file tstrformat.nim imports strformat. If you run the original test case where the import strformat is not present, it still fails.
Using Nim devel (v0.19.9) with the original test case (with two separate files), it works correctly.
Using Nim stable (v0.19.6 or older) it fails with lib/pure/strformat.nim(278, 5) Error: undeclared identifier: 'format', but that is expected as the fix hasn't been backported to the stable version.
You can either use the devel version or wait for v0.20.
Yes, sorry, I was looking at the newer devel tests, but running an older version and 0.19.6.
I've submitted a PR to move the test above the import just in case.
Most helpful comment
We have a plan how to fix it. Templates expecting
untypedparams will be expanded earlier while the body of another template or generic is being read. Thus, the interpolation will produce AST nodes that will bind properly to the template parameters.