nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.23k stars 1.46k forks source link

noRewrite pragma doesn't prevent rewrites #16620

Open exelotl opened 3 years ago

exelotl commented 3 years ago

While playing with term rewriting macros, I found that the {.noRewrite.} pragma doesn't behave as expected at all.

Example

# test 1
# ------

proc get(x: int): int = x

template t{get(a)}(a: int): int =
  {.noRewrite.}:
    get(a) + 1

echo get(0)

# test 2
# ------

var x: int

template asgn{a = b}(a: int{lvalue}, b: int) =
  {.noRewrite.}:
    a = b + 1

x = 10
echo x

Current output

Tested from Nim 0.20.0 to 1.4.2:

49
85

Expected output

1
11

Additional information

The output on Nim 0.19.6 is different, test 2 gives the correct result:

98
11
exelotl commented 3 years ago

Workaround: Depending on the use case, you may be able to use a helper proc defined before the term-rewriting macro, to which the rules of the macro don't apply:

# test 1
# ------

proc get(x: int): int = x

proc getFinal(x: int): int {.inline.} =
  get(x)

template t{get(a)}(a: int): int =
    getFinal(a) + 1

echo get(0)

# test 2
# ------

var x: int

proc asgnFinal[T](a: var T, b: T) {.inline.} =
  a = b

template asgn{a = b}(a: int{lvalue}, b: int) =
  asgnFinal(a, b + 1)

x = 10
echo x

Output:

1
11