nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.55k stars 1.47k forks source link

Internal error when using array of procs #5015

Closed flyx closed 6 years ago

flyx commented 7 years ago
type Mutator* = proc(matched: string): string {.noSideEffect, gcsafe, locks: 0.}

proc putMutated*(
    MutatorCount: static[int],
    mTable: static[array[MutatorCount, Mutator]], input: string) =
  for i in 0..<MutatorCount: echo mTable[i](input)

proc mutator0(matched: string): string =
    "foo"

const
  mTable = [Mutator(mutator0)]

putMutated(1, mTable, "foo")

This yields:

Error: internal error: genAssignment: tyNil
Traceback (most recent call last)
nim.nim(120)             nim
nim.nim(76)              handleCmdLine
main.nim(252)            mainCommand
main.nim(65)             commandCompileToC
modules.nim(240)         compileProject
system.nim(1105)         compileModule
passes.nim(199)          processModule
passes.nim(132)          processTopLevelStmt
cgen.nim(1223)           myProcess
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2060)       expr
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2132)       expr
cgen.nim(782)            genProc
cgen.nim(752)            genProcNoForward
cgen.nim(672)            genProcAux
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2057)       expr
ccgstmts.nim(506)        genBlock
ccgexprs.nim(2060)       expr
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2060)       expr
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2057)       expr
ccgstmts.nim(506)        genBlock
ccgexprs.nim(2081)       expr
ccgstmts.nim(484)        genWhileStmt
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2060)       expr
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2060)       expr
ccgstmts.nim(1121)       genStmts
ccgexprs.nim(2023)       expr
ccgexprs.nim(1731)       genMagicExpr
ccgexprs.nim(933)        genEcho
cgen.nim(451)            initLocExpr
ccgexprs.nim(2029)       expr
ccgexprs.nim(1698)       genMagicExpr
ccgexprs.nim(2031)       expr
ccgcalls.nim(531)        genCall
ccgcalls.nim(206)        genClosureCall
cgen.nim(451)            initLocExpr
ccgexprs.nim(2053)       expr
ccgexprs.nim(875)        genBracketExpr
ccgexprs.nim(806)        genArrayElem
cgen.nim(451)            initLocExpr
ccgexprs.nim(2043)       expr
ccgexprs.nim(1851)       genArrayConstr
ccgexprs.nim(2048)       expr
ccgexprs.nim(1807)       genTupleConstr
ccgexprs.nim(2009)       expr
ccgexprs.nim(413)        putIntoDest
ccgexprs.nim(356)        genAssignment
msgs.nim(999)            internalError
msgs.nim(904)            rawMessage
msgs.nim(901)            rawMessage
msgs.nim(840)            handleError
msgs.nim(824)            quit
FAILURE

Removing the static[] around the parameter of putMutated make the code compile and work as expected.

grokqcd commented 7 years ago

BTW, the code as written (with the static[]) works correctly under nimscript.

zah commented 7 years ago

While this is a valid bug, I don't see a good reason to make the mTable parameter of putMutated static here. This will only make the putMutated proc generic, which will lead to unnecessary code bloat. The code works fine if mTable is a normal array or openarray parameter.

jangko commented 6 years ago

this maybe related

type
  helloProc = proc(): int

proc hello(): int =
  echo "hello"
  result = 1

let procs1 = [hello.helloProc]
const procs2 = [hello.helloProc]

echo procs1[0]()      # ok
#echo procs2[0]()    # failed to compile with `internal error: genAssignment: tyNil`

helloProc is a closure proc type, but proc hello is not, but why it works with let in the first place? this conversion should be forbidden.

or the compiler could suggest something like:

please try to change `helloProc = proc(): int` into `helloProc = proc(): int {.nimcall.}`

this snippet below show without conversion both let and const works.

proc hello(): int =
  echo "hello"
  result = 1

let procs1 = [hello]
const procs2 = [hello]

echo procs1[0]()
echo procs2[0]()
Araq commented 6 years ago

this conversion should be forbidden.

No, why? The spec says that conversions from nimcall to closure are allowed.