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.49k stars 1.46k forks source link

Compiler crash in mapType #16867

Open yglukhov opened 3 years ago

yglukhov commented 3 years ago
import macros

type
  Env = ptr object
    a: int

macro testAux(foo: untyped): untyped =
  # This macro takes the body of proc `foo`, puts its body into new proc `newFoo`, that accepts Env as argument :env,
  # and replaces reference to `a` with `:env.a`
  foo.expectKind(nnkProcDef)
  let
    envParamId = genSym(nskParam, ":env")
    newParamName = ident"a"
  let newFoo = newProc(ident"newFoo",
                  params = [newEmptyNode(), newIdentDefs(envParamId, ident"Env")],
                  body = foo.body)

  let echoCall = newFoo.body
  echoCall.expectKind(nnkCommand)
  let hiddenCallConv = echoCall[1][1][0]
  hiddenCallConv.expectKind(nnkHiddenCallConv)

  # Make sure we're replacing the right thing
  doAssert(hiddenCallConv[1].kind == nnkSym and $hiddenCallConv[1] == "a")

  # Replace `a` with :env.a

  # Internal error line. Replace `a` with `:env.a`
  hiddenCallConv[1] = newDotExpr(envParamId, newParamName)

  # Nim crash line. Replace `a` with `:env[].a`
  hiddenCallConv[1] = newDotExpr(newTree(nnkDerefExpr, envParamId), newParamName)

  result = newFoo

  echo repr(result) # This gets printed nicely and looks correct

# Force some initial typing
macro test(foo: typed): untyped =
  result = newCall("testAux", foo)

proc foo(a: int) {.test.} =
  echo a

newFoo(nil)
nim c test.nim
Traceback (most recent call last)
.../nim-devel/compiler/nim.nim(119) nim
.../nim-devel/compiler/nim.nim(84) handleCmdLine
.../nim-devel/compiler/main.nim(242) mainCommand
.../nim-devel/compiler/main.nim(213) compileToBackend
.../nim-devel/compiler/main.nim(90) commandCompileToC
.../nim-devel/compiler/modules.nim(178) compileProject
.../nim-devel/compiler/modules.nim(102) compileModule
.../nim-devel/compiler/passes.nim(180) processModule
.../nim-devel/compiler/passes.nim(73) processTopLevelStmt
.../nim-devel/compiler/cgen.nim(1912) myProcess
.../nim-devel/compiler/cgen.nim(1906) genTopLevelStmt
.../nim-devel/compiler/cgen.nim(992) genProcBody
.../nim-devel/compiler/ccgstmts.nim(1589) genStmts
.../nim-devel/compiler/ccgexprs.nim(2799) expr
.../nim-devel/compiler/ccgcalls.nim(783) genCall
.../nim-devel/compiler/ccgcalls.nim(780) genAsgnCall
.../nim-devel/compiler/ccgcalls.nim(379) genPrefixCall
.../nim-devel/compiler/cgen.nim(619) initLocExpr
.../nim-devel/compiler/ccgexprs.nim(2727) expr
.../nim-devel/compiler/cgen.nim(1211) genProc
.../nim-devel/compiler/cgen.nim(1185) genProcNoForward
.../nim-devel/compiler/cgen.nim(1051) genProcAux
.../nim-devel/compiler/cgen.nim(992) genProcBody
.../nim-devel/compiler/ccgstmts.nim(1589) genStmts
.../nim-devel/compiler/ccgexprs.nim(2797) expr
.../nim-devel/compiler/ccgexprs.nim(2391) genMagicExpr
.../nim-devel/compiler/ccgexprs.nim(1133) genEcho
.../nim-devel/compiler/cgen.nim(619) initLocExpr
.../nim-devel/compiler/ccgexprs.nim(2817) expr
.../nim-devel/compiler/ccgexprs.nim(2525) genArrayConstr
.../nim-devel/compiler/ccgexprs.nim(2803) expr
.../nim-devel/compiler/ccgexprs.nim(1727) genMagicExpr
.../nim-devel/compiler/cgen.nim(619) initLocExpr
.../nim-devel/compiler/ccgexprs.nim(2831) expr
.../nim-devel/compiler/ccgexprs.nim(845) genRecordField
.../nim-devel/compiler/ccgexprs.nim(807) genRecordFieldAux
.../nim-devel/compiler/cgen.nim(619) initLocExpr
.../nim-devel/compiler/ccgexprs.nim(2830) expr
.../nim-devel/compiler/ccgexprs.nim(728) genDeref
.../nim-devel/compiler/ccgtypes.nim(146) mapType
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
FAILURE

The crash will happen after macro evaluation. repr result at the end of the macro looks valid to me. If you comment the "crash" line in the sample, there will be ICE Error: internal error: genRecordFieldAux. The repr result is slightly different but still valid.

yglukhov commented 3 years ago

It seems the problem appears only when replacing the sym in echo. If echo is changed to a non-magic function, the code will work (with some modifications, as it only works with echo-specific ast)

timotheecour commented 3 years ago

likely duplicate of https://github.com/nim-lang/Nim/issues/18561 (https://github.com/nim-lang/Nim/issues/18561 has more info)

metagn commented 1 week ago

nkHiddenCallConv is entirely ignored in semchecking, hence its children including the gensym symbol aren't typed.