Skip to content

Commit e05448b

Browse files
authored
fix miscompilation with indirect tail calls (nim-works#1573)
## Summary Fix a bug with the tail call elimination that caused target compiler errors, or run-time errors, with the JS and C targets, in some edge cases involving indirect tail calls. ## Details In the MIR type IR, there are no `sink` types, meaning that `proc(x: sink T)` and `proc(x: T)` map to the same type representation -- the one first registered with the environment is considered the canonical one. The tail call elimination looked up the `PType` for the canonical type of `.tailcall` procvals, yielding a `PType that's not the original for the MIR type that's not the canonical one. Since the `sink` modifier is significant for the parameter tuple type creation, this led to the tuple having the wrong type for one of the indirect calls. The lookup is changed to use the original instead of the canonical MIR type, fixing the problem. A regression test reproducing the problem is added.
1 parent ec117c4 commit e05448b

File tree

2 files changed

+20
-1
lines changed

2 files changed

+20
-1
lines changed

compiler/mir/tailcall_elim.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ proc getCalleeType(tree: MirTree, pos: NodePosition, env: MirEnv): PType =
3232
if tree[pos].kind == mnkProc:
3333
env[tree[pos].prc].typ
3434
else:
35-
env.types[env.types.canonical(tree[pos].typ)]
35+
env.types[tree[pos].typ].skipTypes(abstractInst)
3636

3737
proc emitParamBlobInit(bu: var MirBuilder, tree: MirTree, call: NodePosition,
3838
to: Value, g: ModuleGraph, owner: PSym,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
discard """
2+
description: "Regression test for internal tail call transformation bug"
3+
"""
4+
5+
type Object = object
6+
## a type that uses pass-by-ref internally
7+
arr: array[4, int]
8+
9+
proc a(x: Object): Object {.tailcall.} =
10+
x
11+
12+
proc b(x: sink Object): Object {.tailcall.} =
13+
x
14+
15+
# the procedure with the non-sink parameter must be used first
16+
let ia = a
17+
let ib = b
18+
doAssert ia(Object(arr: [1, 2, 3, 4])).arr == [1, 2, 3, 4]
19+
doAssert ib(Object(arr: [1, 2, 3, 4])).arr == [1, 2, 3, 4]

0 commit comments

Comments
 (0)