Nim
Nim copied to clipboard
modifying typed params in macros (even after copyNimTree) gives SIGSEGV (a`typ`is nil)
Example
when true:
import macros
macro bar(n: typed): untyped =
var n = n.copyNimTree # without this, you get: Error: typechecked nodes may not be modified
let tmp = genSym(nskLet, "tmp")
let j = n[1][0][0]
n[1][0][0] = tmp
result = quote do:
let `tmp` = `j`
let lhs = `n`
echo result.repr
type
A = object
x: int
PA = ref A
proc fn(c: int): int = c
let a = PA()
bar(fn(a[].x))
Current Output
# result of result.repr:
let tmp_805306395 = a
let lhs`gensym0 = fn(tmp_805306395[].x)
SIGSEGV
Expected Output
works
note 1
with bar(a[].x.fn) instead of bar(fn(a[].x)), removing var n = n.copyNimTree doesn't give Error: typechecked nodes may not be modified, but this still crashes with SIGSEGV
note that the treeRepr of the input n is:
Call
Sym "fn"
DotExpr
DerefExpr
Sym "a"
Sym "x";
note 2
here's a stacktrace with a debug version of nim: https://gist.github.com/timotheecour/23520a5e868d674c23ffd7d9148f304d
it crashes because typ was nil:
proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind =
## Maps a Nim type to a C type
case typ.kind
note 3
instrumenting code with astalgo.debug on the result of bar gives:
without n[1][0][0] = tmp: no crash, produces this:
https://gist.github.com/timotheecour/280550dad2b2656f579f7baf12b27a8e
with n[1][0][0] = tmp: crash with SIGSEGV, produces this:
https://gist.github.com/timotheecour/cf626ba2eb2b51279167fc1adba2f26b
the relevant difference between those 2 is that the node with kind nkDerefExpr has ((near line 43):
"typ": "tyRef",
vs
"typ": "nil",
note 4
adding calls to copyNimTree does not help, nor does doing it manually via:
proc copy2(a: NimNode): NimNode =
result = a.copyNimNode
for i in 0..<a.len: result.add copy2(a[i])
Additional Information
1.5.1 0c4582c66524d58a3c72827d9546a5c5f1c40286
this impacts macros operating on types inputs, and I'm encountering this in std/wrapnils when trying to improve the ?. macro, specifically such that the sub-expression inside a function call (fn in this case) isn't re-computed.