From 71801c2b8f7eb080421aae9140cd15c5fcc34efd Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 12 Jun 2023 07:34:34 +0300 Subject: [PATCH] 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 --- compiler/ast.nim | 3 +- compiler/renderer.nim | 1 + compiler/semtempl.nim | 8 +++++ tests/lexer/tcustom_numeric_literals.nim | 38 ++++++++++-------------- tests/template/mdotcall.nim | 22 ++++++++++++++ tests/template/tdotcall.nim | 10 +++++++ 6 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 tests/template/mdotcall.nim create mode 100644 tests/template/tdotcall.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 8fba0a848716..f8aefd8fb15f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 diff --git a/compiler/renderer.nim b/compiler/renderer.nim index f0ad21815ccf..3f237c932255 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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 & "\"\"\"" diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 9edb2d0ca55d..33f4c11995b7 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -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: diff --git a/tests/lexer/tcustom_numeric_literals.nim b/tests/lexer/tcustom_numeric_literals.nim index 9c49d0c0818a..35b4803d36c1 100644 --- a/tests/lexer/tcustom_numeric_literals.nim +++ b/tests/lexer/tcustom_numeric_literals.nim @@ -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() diff --git a/tests/template/mdotcall.nim b/tests/template/mdotcall.nim new file mode 100644 index 000000000000..38a6ccae0da8 --- /dev/null +++ b/tests/template/mdotcall.nim @@ -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 diff --git a/tests/template/tdotcall.nim b/tests/template/tdotcall.nim new file mode 100644 index 000000000000..abcbc8bd5a17 --- /dev/null +++ b/tests/template/tdotcall.nim @@ -0,0 +1,10 @@ +import mdotcall + +# issue #20073 +works() +boom() + +# issue #7085 +doAssert baz("hello") == "hellobar" +doAssert baz"hello" == "hellobar" +doAssert "hello".baz == "hellobar"