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

Fail to read a value from CacheTable in compileTime proc called from compileTime proc #22285

Open demotomohiro opened 1 year ago

demotomohiro commented 1 year ago

Description

I added a value to CacheTable in macrocache module and tried to read a key from it in compileTime proc, but didn't get a value as if it is emtpy.

Run following code with nim c testmc.nim:

testmc.nim

import macrocache

const ctable = CacheTable"ctable"

proc getString(ctable: CacheTable): string {.compileTime.} =
  for key, val in ctable:
    result = key

proc test() {.compileTime.} =
  ctable["Key In CacheTable"] = nil
  var a = getString(ctable)
  echo a

static:
  test()

Nim Version

Nim Compiler Version 1.9.5 [Linux: amd64]
Compiled at 2023-07-15
Copyright (c) 2006-2023 by Andreas Rumpf

git hash: f9280090f623d8fddbf753ec50e0ecd21f388d00
active boot switches: -d:release

Current Output

(No output)

Expected Output

Key In CacheTable

Possible Solution

No response

Additional Information

Following code works:

import macrocache

const ctable = CacheTable"ctable"

proc getString(ctable: CacheTable): string {.compileTime.} =
  for key, val in ctable:
    result = key

static:
  ctable["Key In CacheTable"] = nil
  var a = getString(ctable)
  echo a
import macrocache

const ctable = CacheTable"ctable"

proc test() {.compileTime.} =
  ctable["Key In CacheTable"] = nil
  var a: string
  for key, val in ctable:
    a = key
  echo a

static:
  test()

So it looks like calling compileTime procedure from compileTime procedure causing this bug.

Graveflo commented 1 year ago

this also works:

import macrocache

const ctableM = CacheTable"ctable"

proc getString(): string =
  for key, val in ctableM:
    result = key

proc test() {.compileTime.} =
  ctableM["Key In CacheTable"] = nil
  var a = getString()
  echo a

static:
  test()

Indeed getString being called inside a proc with both tagged as compileTime causes it to be run off the rip. This kind of makes sense if you assume that test is going to be parsed in full before the VM starts evaluating the instructions, but it's probably not preferable. To be clear, this is happening because getString is running before test's body

Edit: It's running before test is even called actually.

I think this has something to do with the inner proc having a return value, because the order is correct when there is no return type specified:

proc l1_1(): int {.compileTime.} =
  echo "l1_1"

proc test() {.compileTime.} =
  echo "test"
  discard l1_1()

proc l3(): int {.compileTime.} =
  echo "l3"

proc l2() {.compiletime.} = 
  echo "l2"
  discard l3()

proc test2() {. compileTime .} =
  echo "test2"
  l2()

static:
  echo "static"
  test()
  test2()