mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-20 16:01:29 +00:00
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:
@@ -2203,10 +2203,13 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
if ids.len > 0:
|
||||
dummyTemplate[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
|
||||
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
|
||||
ids.add c.graph.emptyNode # no default value
|
||||
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids)
|
||||
|
||||
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
|
||||
for i in 1..<ids.len:
|
||||
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)
|
||||
quotes[0] = tmpl[namePos]
|
||||
# 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.
|
||||
## An instruction is 1-3 int32s in memory, it is a register based VM.
|
||||
|
||||
|
||||
import semmacrosanity
|
||||
import
|
||||
std/[strutils, tables, parseutils],
|
||||
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:
|
||||
let node = regs[rb+i].regToNode
|
||||
node.info = c.debug[pc]
|
||||
if prc.typ[i].kind notin {tyTyped, tyUntyped}:
|
||||
node.annotateType(prc.typ[i], c.config)
|
||||
|
||||
macroCall.add(node)
|
||||
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]
|
||||
|
||||
@@ -83,7 +83,7 @@ pkg "iterutils"
|
||||
pkg "jstin"
|
||||
pkg "karax", "nim c -r tests/tester.nim"
|
||||
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 "macroutils"
|
||||
pkg "manu"
|
||||
@@ -115,7 +115,7 @@ pkg "nimpy", "nim c -r tests/nimfrompy.nim"
|
||||
pkg "nimquery"
|
||||
pkg "nimsl"
|
||||
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 "nimx", "nim c --threads:on test/main.nim", allowFailure = true
|
||||
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 "rbtree"
|
||||
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 "RollingHash", "nim c -r tests/test_cyclichash.nim"
|
||||
pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim"
|
||||
|
||||
@@ -175,3 +175,139 @@ block getCustomPragmaValGeneric:
|
||||
var f: Foo[string]
|
||||
doAssert f.getCustomPragmaVal(examplePragma) == 42
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user