track introduced locals in vmgen for eval check (#24674)

fixes #8758, fixes #10828, fixes #12172, fixes #21610, fixes #23803,
fixes #24633, fixes #24634, succeeds #24085

We simply track the symbol ID of every traversed `var`/`let` definition
in `vmgen`, then these symbols are always considered evaluable in the
current `vmgen` context. The set of symbols is reset before every
generation, but both tests worked properly without doing this including
the nested `const`, so maybe it's already done in some way I'm not
seeing.

(cherry picked from commit a5cc33c1d3)
This commit is contained in:
metagn
2025-02-14 22:54:17 +03:00
committed by narimiran
parent b740e8cca8
commit bcecce885f
7 changed files with 115 additions and 3 deletions

View File

@@ -12,7 +12,7 @@
import semmacrosanity
import
std/[strutils, tables, parseutils],
std/[strutils, tables, intsets, parseutils],
msgs, vmdef, vmgen, nimsets, types,
parser, vmdeps, idents, trees, renderer, options, transf,
gorgeimpl, lineinfos, btrees, macrocacheimpl,
@@ -2425,9 +2425,12 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
setupGlobalCtx(module, g, idgen)
var c = PCtx g.vm
let oldMode = c.mode
let oldLocals = c.locals
c.mode = mode
c.locals = initIntSet()
c.cannotEval = false
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
c.locals = oldLocals
if c.cannotEval:
return errorNode(idgen, prc, n)
if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info)

View File

@@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import std/[tables, strutils]
import std/[tables, strutils, intsets]
import ast, idents, options, modulegraphs, lineinfos
@@ -272,6 +272,7 @@ type
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
procToCodePos*: Table[int, int]
cannotEval*: bool
locals*: IntSet
PStackFrame* = ref TStackFrame
TStackFrame* {.acyclic.} = object

View File

@@ -1583,6 +1583,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
# are in the right scope:
if sfGenSym in s.flags and c.prc.sym == nil: discard
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
elif s.kind in {skVar, skLet} and s.id in c.locals: discard
else: cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
@@ -1975,7 +1976,7 @@ proc genVarSection(c: PCtx; n: PNode) =
c.gen(lowerTupleUnpacking(c.graph, a, c.idgen, c.getOwner))
elif a[0].kind == nkSym:
let s = a[0].sym
checkCanEval(c, a[0])
c.locals.incl(s.id)
if s.isGlobal:
let runtimeAccessToCompileTime = c.mode == emRepl and
sfCompileTime in s.flags and s.position > 0