mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
fix dot calls with resolved symbols in templates (#22076)
* fix dot calls with resolved symbols in templates * make old code work * fix custom number literals test * remove leftover debug marker * enable "bug 9" test too * fix renderer, add test for #7085
This commit is contained in:
@@ -1128,11 +1128,10 @@ const
|
||||
|
||||
proc getPIdent*(a: PNode): PIdent {.inline.} =
|
||||
## Returns underlying `PIdent` for `{nkSym, nkIdent}`, or `nil`.
|
||||
# xxx consider whether also returning the 1st ident for {nkOpenSymChoice, nkClosedSymChoice}
|
||||
# which may simplify code.
|
||||
case a.kind
|
||||
of nkSym: a.sym.name
|
||||
of nkIdent: a.ident
|
||||
of nkOpenSymChoice, nkClosedSymChoice: a.sons[0].sym.name
|
||||
else: nil
|
||||
|
||||
const
|
||||
|
||||
@@ -379,6 +379,7 @@ proc atom(g: TSrcGen; n: PNode): string =
|
||||
of nkEmpty: result = ""
|
||||
of nkIdent: result = n.ident.s
|
||||
of nkSym: result = n.sym.name.s
|
||||
of nkClosedSymChoice, nkOpenSymChoice: result = n[0].sym.name.s
|
||||
of nkStrLit: result = ""; result.addQuoted(n.strVal)
|
||||
of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"'
|
||||
of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
|
||||
|
||||
@@ -561,6 +561,14 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
inc c.noGenSym
|
||||
result[1] = semTemplBody(c, n[1])
|
||||
dec c.noGenSym
|
||||
if result[1].kind == nkSym and result[1].sym.kind in routineKinds:
|
||||
# prevent `dotTransformation` from rewriting this node to `nkIdent`
|
||||
# by making it a symchoice
|
||||
# in generics this becomes `nkClosedSymChoice` but this breaks code
|
||||
# as the old behavior here was that this became `nkIdent`
|
||||
var choice = newNodeIT(nkOpenSymChoice, n[1].info, newTypeS(tyNone, c.c))
|
||||
choice.add result[1]
|
||||
result[1] = choice
|
||||
else:
|
||||
result = semTemplBodySons(c, n)
|
||||
of nkExprColonExpr, nkExprEqExpr:
|
||||
|
||||
@@ -134,17 +134,14 @@ template main =
|
||||
|
||||
block: # bug 1 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
|
||||
macro deb1(a): untyped = newLit a.repr
|
||||
macro deb2(a): untyped = newLit a.lispRepr
|
||||
macro deb2(a): untyped =
|
||||
a[1] = ident($a[1])
|
||||
newLit a.lispRepr
|
||||
doAssert deb1(-12'wrap) == "-12'wrap"
|
||||
doAssert deb1(-12'nonexistent) == "-12'nonexistent"
|
||||
doAssert deb2(-12'nonexistent) == """(DotExpr (RStrLit "-12") (Ident "\'nonexistent"))"""
|
||||
when false: # xxx bug:
|
||||
# this holds:
|
||||
doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Sym "wrap2"))"""
|
||||
doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Sym "\'wrap"))"""
|
||||
# but instead this should hold:
|
||||
doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Ident "wrap2"))"""
|
||||
doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Ident "\'wrap"))"""
|
||||
doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Ident "wrap2"))"""
|
||||
doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Ident "\'wrap"))"""
|
||||
|
||||
block: # bug 2 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
|
||||
template toSuf(`'suf`): untyped =
|
||||
@@ -165,21 +162,16 @@ template main =
|
||||
doAssert fn2() == "[[-12]]"
|
||||
doAssert fn3() == "[[-12]]"
|
||||
|
||||
when false: # xxx this fails; bug 9 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
|
||||
#[
|
||||
possible workaround: use `genAst` (https://github.com/nim-lang/Nim/pull/17426) and this:
|
||||
let a3 = `'wrap3`("-128")
|
||||
]#
|
||||
block:
|
||||
macro metawrap(): untyped =
|
||||
func wrap1(a: string): string = "{" & a & "}"
|
||||
func `'wrap3`(a: string): string = "{" & a & "}"
|
||||
result = quote do:
|
||||
let a1 = wrap1"-128"
|
||||
let a2 = -128'wrap3
|
||||
metawrap()
|
||||
doAssert a1 == "{-128}"
|
||||
doAssert a2 == "{-128}"
|
||||
block: # bug 9 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
|
||||
macro metawrap(): untyped =
|
||||
func wrap1(a: string): string = "{" & a & "}"
|
||||
func `'wrap3`(a: string): string = "{" & a & "}"
|
||||
result = quote do:
|
||||
let a1 {.inject.} = wrap1"-128"
|
||||
let a2 {.inject.} = -128'wrap3
|
||||
metawrap()
|
||||
doAssert a1 == "{-128}"
|
||||
doAssert a2 == "{-128}"
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
22
tests/template/mdotcall.nim
Normal file
22
tests/template/mdotcall.nim
Normal file
@@ -0,0 +1,22 @@
|
||||
# issue #20073
|
||||
|
||||
type Foo = object
|
||||
proc foo(f: Foo) = discard
|
||||
|
||||
template works*() =
|
||||
var f: Foo
|
||||
foo(f)
|
||||
|
||||
template boom*() =
|
||||
var f: Foo
|
||||
f.foo() # Error: attempting to call undeclared routine: 'foo'
|
||||
f.foo # Error: undeclared field: 'foo' for type a.Foo
|
||||
|
||||
# issue #7085
|
||||
|
||||
proc bar(a: string): string =
|
||||
return a & "bar"
|
||||
|
||||
template baz*(a: string): string =
|
||||
var b = a.bar()
|
||||
b
|
||||
10
tests/template/tdotcall.nim
Normal file
10
tests/template/tdotcall.nim
Normal file
@@ -0,0 +1,10 @@
|
||||
import mdotcall
|
||||
|
||||
# issue #20073
|
||||
works()
|
||||
boom()
|
||||
|
||||
# issue #7085
|
||||
doAssert baz("hello") == "hellobar"
|
||||
doAssert baz"hello" == "hellobar"
|
||||
doAssert "hello".baz == "hellobar"
|
||||
Reference in New Issue
Block a user