fixes #21326; fixes #7375; fixes #11986; fixes #9607; rework quote do; getAst uses type info to annotate the type of quoted variables; no more type erasures for quoted variables (#21433)
* fixes #21326; getAst uses type info to annotateType quoted variables * simplify logics; sem types first * fixes important packages * add testcases * tiny
This commit is contained in:
parent
070938720a
commit
9948fed919
4 changed files with 150 additions and 8 deletions
|
|
@ -2203,10 +2203,13 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||||
if ids.len > 0:
|
if ids.len > 0:
|
||||||
dummyTemplate[paramsPos] = newNodeI(nkFormalParams, n.info)
|
dummyTemplate[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||||
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
|
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
|
||||||
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
|
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
|
||||||
ids.add c.graph.emptyNode # no default value
|
for i in 1..<ids.len:
|
||||||
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids)
|
let typ = semExprWithType(c, quotes[i+1], {}).typ
|
||||||
|
if tfTriggersCompileTime notin typ.flags:
|
||||||
|
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], newNodeIT(nkType, n.info, typ), c.graph.emptyNode)
|
||||||
|
else:
|
||||||
|
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
|
||||||
var tmpl = semTemplateDef(c, dummyTemplate)
|
var tmpl = semTemplateDef(c, dummyTemplate)
|
||||||
quotes[0] = tmpl[namePos]
|
quotes[0] = tmpl[namePos]
|
||||||
# This adds a call to newIdentNode("result") as the first argument to the template call
|
# This adds a call to newIdentNode("result") as the first argument to the template call
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
## This file implements the new evaluation engine for Nim code.
|
## This file implements the new evaluation engine for Nim code.
|
||||||
## An instruction is 1-3 int32s in memory, it is a register based VM.
|
## An instruction is 1-3 int32s in memory, it is a register based VM.
|
||||||
|
|
||||||
|
import semmacrosanity
|
||||||
import
|
import
|
||||||
std/[strutils, tables, parseutils],
|
std/[strutils, tables, parseutils],
|
||||||
msgs, vmdef, vmgen, nimsets, types, passes,
|
msgs, vmdef, vmgen, nimsets, types, passes,
|
||||||
|
|
@ -1408,6 +1408,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
for i in 1..rc-1:
|
for i in 1..rc-1:
|
||||||
let node = regs[rb+i].regToNode
|
let node = regs[rb+i].regToNode
|
||||||
node.info = c.debug[pc]
|
node.info = c.debug[pc]
|
||||||
|
if prc.typ[i].kind notin {tyTyped, tyUntyped}:
|
||||||
|
node.annotateType(prc.typ[i], c.config)
|
||||||
|
|
||||||
macroCall.add(node)
|
macroCall.add(node)
|
||||||
var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen)
|
var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen)
|
||||||
if a.kind == nkStmtList and a.len == 1: a = a[0]
|
if a.kind == nkStmtList and a.len == 1: a = a[0]
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ pkg "iterutils"
|
||||||
pkg "jstin"
|
pkg "jstin"
|
||||||
pkg "karax", "nim c -r tests/tester.nim"
|
pkg "karax", "nim c -r tests/tester.nim"
|
||||||
pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree"
|
pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree"
|
||||||
pkg "loopfusion"
|
pkg "loopfusion", url = "https://github.com/nim-lang/loop-fusion"
|
||||||
pkg "lockfreequeues"
|
pkg "lockfreequeues"
|
||||||
pkg "macroutils"
|
pkg "macroutils"
|
||||||
pkg "manu"
|
pkg "manu"
|
||||||
|
|
@ -115,7 +115,7 @@ pkg "nimpy", "nim c -r tests/nimfrompy.nim"
|
||||||
pkg "nimquery"
|
pkg "nimquery"
|
||||||
pkg "nimsl"
|
pkg "nimsl"
|
||||||
pkg "nimsvg"
|
pkg "nimsvg"
|
||||||
pkg "nimterop", "nimble minitest"
|
pkg "nimterop", "nimble minitest", url = "https://github.com/nim-lang/nimterop"
|
||||||
pkg "nimwc", "nim c nimwc.nim", allowFailure = true
|
pkg "nimwc", "nim c nimwc.nim", allowFailure = true
|
||||||
pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true
|
pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true
|
||||||
pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
|
pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
|
||||||
|
|
@ -135,7 +135,7 @@ pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim"
|
||||||
pkg "pylib"
|
pkg "pylib"
|
||||||
pkg "rbtree"
|
pkg "rbtree"
|
||||||
pkg "react", "nimble example"
|
pkg "react", "nimble example"
|
||||||
pkg "regex", "nim c src/regex"
|
pkg "regex", "nim c src/regex", url = "https://github.com/nim-lang/nim-regex"
|
||||||
pkg "result", "nim c -r result.nim"
|
pkg "result", "nim c -r result.nim"
|
||||||
pkg "RollingHash", "nim c -r tests/test_cyclichash.nim"
|
pkg "RollingHash", "nim c -r tests/test_cyclichash.nim"
|
||||||
pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim"
|
pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim"
|
||||||
|
|
|
||||||
|
|
@ -175,3 +175,139 @@ block getCustomPragmaValGeneric:
|
||||||
var f: Foo[string]
|
var f: Foo[string]
|
||||||
doAssert f.getCustomPragmaVal(examplePragma) == 42
|
doAssert f.getCustomPragmaVal(examplePragma) == 42
|
||||||
doAssert f.x.getCustomPragmaVal(examplePragma) == 25
|
doAssert f.x.getCustomPragmaVal(examplePragma) == 25
|
||||||
|
|
||||||
|
block: # bug #21326
|
||||||
|
macro foo(body: untyped): untyped =
|
||||||
|
let a = body.lineInfoObj()
|
||||||
|
let aLit = a.newLit
|
||||||
|
result = quote do:
|
||||||
|
doAssert $`a` == $`aLit`
|
||||||
|
|
||||||
|
foo:
|
||||||
|
let c = 1
|
||||||
|
|
||||||
|
template name(a: LineInfo): untyped =
|
||||||
|
discard a # `aLit` works though
|
||||||
|
|
||||||
|
macro foo3(body: untyped): untyped =
|
||||||
|
let a = body.lineInfoObj()
|
||||||
|
# let ax = newLit(a)
|
||||||
|
result = getAst(name(a))
|
||||||
|
|
||||||
|
foo3:
|
||||||
|
let c = 1
|
||||||
|
|
||||||
|
block: # bug #7375
|
||||||
|
macro fails(b: static[bool]): untyped =
|
||||||
|
doAssert b == false
|
||||||
|
result = newStmtList()
|
||||||
|
|
||||||
|
macro foo(): untyped =
|
||||||
|
|
||||||
|
var b = false
|
||||||
|
|
||||||
|
## Fails
|
||||||
|
result = quote do:
|
||||||
|
fails(`b`)
|
||||||
|
|
||||||
|
foo()
|
||||||
|
|
||||||
|
macro someMacro(): untyped =
|
||||||
|
template tmpl(boolean: bool) =
|
||||||
|
when boolean:
|
||||||
|
discard "it's true!"
|
||||||
|
else:
|
||||||
|
doAssert false
|
||||||
|
result = getAst(tmpl(true))
|
||||||
|
|
||||||
|
someMacro()
|
||||||
|
|
||||||
|
block:
|
||||||
|
macro foo(): untyped =
|
||||||
|
result = quote do: `littleEndian`
|
||||||
|
|
||||||
|
doAssert littleEndian == foo()
|
||||||
|
|
||||||
|
block:
|
||||||
|
macro eqSym(x, y: untyped): untyped =
|
||||||
|
let eq = $x == $y # Unfortunately eqIdent compares to string.
|
||||||
|
result = quote do: `eq`
|
||||||
|
|
||||||
|
var r, a, b: int
|
||||||
|
|
||||||
|
template fma(result: var int, a, b: int, op: untyped) =
|
||||||
|
# fused multiple-add
|
||||||
|
when eqSym(op, `+=`):
|
||||||
|
discard "+="
|
||||||
|
else:
|
||||||
|
discard "+"
|
||||||
|
|
||||||
|
fma(r, a, b, `+=`)
|
||||||
|
|
||||||
|
block:
|
||||||
|
template test(boolArg: bool) =
|
||||||
|
static:
|
||||||
|
doAssert typeof(boolArg) is bool
|
||||||
|
let x: bool = boolArg # compile error here, because boolArg became an int
|
||||||
|
|
||||||
|
macro testWrapped1(boolArg: bool): untyped =
|
||||||
|
# forwarding boolArg directly works
|
||||||
|
result = getAst(test(boolArg))
|
||||||
|
|
||||||
|
macro testWrapped2(boolArg: bool): untyped =
|
||||||
|
# forwarding boolArg via a local variable also works
|
||||||
|
let b = boolArg
|
||||||
|
result = getAst(test(b))
|
||||||
|
|
||||||
|
macro testWrapped3(boolArg: bool): untyped =
|
||||||
|
# but using a literal `true` as a local variable will be converted to int
|
||||||
|
let b = true
|
||||||
|
result = getAst(test(b))
|
||||||
|
|
||||||
|
test(true) # ok
|
||||||
|
testWrapped1(true) # ok
|
||||||
|
testWrapped2(true) # ok
|
||||||
|
testWrapped3(true)
|
||||||
|
|
||||||
|
block:
|
||||||
|
macro foo(): untyped =
|
||||||
|
var s = { 'a', 'b' }
|
||||||
|
quote do:
|
||||||
|
let t = `s`
|
||||||
|
doAssert $typeof(t) == "set[char]"
|
||||||
|
|
||||||
|
foo()
|
||||||
|
|
||||||
|
block: # bug #9607
|
||||||
|
proc fun1(info:LineInfo): string = "bar"
|
||||||
|
proc fun2(info:int): string = "bar"
|
||||||
|
|
||||||
|
macro echoL(args: varargs[untyped]): untyped =
|
||||||
|
let info = args.lineInfoObj
|
||||||
|
let fun1 = bindSym"fun1"
|
||||||
|
let fun2 = bindSym"fun2"
|
||||||
|
|
||||||
|
# this would work instead
|
||||||
|
# result = newCall(bindSym"fun2", info.line.newLit)
|
||||||
|
|
||||||
|
result = quote do:
|
||||||
|
|
||||||
|
# BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil
|
||||||
|
`fun1`(`info`)
|
||||||
|
|
||||||
|
macro echoM(args: varargs[untyped]): untyped =
|
||||||
|
let info = args.lineInfoObj
|
||||||
|
let fun1 = bindSym"fun1"
|
||||||
|
let fun2 = bindSym"fun2"
|
||||||
|
|
||||||
|
# this would work instead
|
||||||
|
# result = newCall(bindSym"fun2", info.line.newLit)
|
||||||
|
|
||||||
|
result = quote do:
|
||||||
|
|
||||||
|
# BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil
|
||||||
|
`fun2`(`info`.line)
|
||||||
|
|
||||||
|
|
||||||
|
doAssert echoL() == "bar"
|
||||||
|
doAssert echoM() == "bar"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue