Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getAst: static int is rkNone within called macro scope #24610

Open
mratsim opened this issue Jan 11, 2025 · 3 comments
Open

getAst: static int is rkNone within called macro scope #24610

mratsim opened this issue Jan 11, 2025 · 3 comments

Comments

@mratsim
Copy link
Collaborator

mratsim commented Jan 11, 2025

When using getAst to capture a macro output, static int have no values.
The error is Error: opcAsgnInt: got rkNone

Test case:

import macros

macro ccopy2[N: static int](a0: var array[N, uint64], b0: array[N, uint64], ctl0: uint64): untyped =

  echo N # This has value rkNone in getAst, comment this out and it "works"

  result = quote do:
    if `ctl0` != 0:
      for i in 0 ..< `N`: # The N disappears in `toStrLit`
        `a0`[i] = `b0`[i]

macro capture_macro_lit2[N: static int](a1: var array[N, uint64], b1: array[N, uint64], ctl1: uint64): untyped =
  result = newStmtList()
  let ast = getAst(ccopy2(a1, b1, ctl1))

  result.add ast.toStrLit()

proc capture_macro_str2(): string =
  var a, b: array[2, uint64]
  var ctl: uint64
  capture_macro_lit2(a, b, ctl)

echo capture_macro_str2()
@metagn
Copy link
Collaborator

metagn commented Jan 11, 2025

Edit: The generalization in this comment is different from the issue specific to getAst here, statics work to an extent

import macros

macro ccopy2[T]() =
  echo T
  
ccopy2[int]() # GenericParam

Generic parameters in macro bodies do not work in general. While this is mostly because macro bodies are not considered generic and never instantiated (#12868), the compiler could still treat them as NimNode values like regular parameters, i.e. at least so this could work:

import macros

macro ccopy2[T](): untyped =
  result = quote do:
    `T`
  # ideally `result = T` would be enough
  
var x: ccopy2[int]()

Templates work similarly and handle the case where they are inferred:

template ccopy2[T](x: T): untyped =
  T
  
var x: ccopy2(123)
echo typeof(x) # int

@mratsim
Copy link
Collaborator Author

mratsim commented Jan 13, 2025

Generic parameters in macro bodies do not work in general.

I use them extensively here: https://github.com/mratsim/constantine/blob/2582fb5/constantine/math/arithmetic/assembly/limbs_asm_mul_x86.nim#L27-L42

macro mul_gen[rLen, aLen, bLen: static int](r_PIR: var Limbs[rLen], a_MEM: Limbs[aLen], b_MEM: Limbs[bLen]) =
  ## Bigint multiplication generator
  ## `a`, `b`, `r` can have a different number of limbs
  ## if `r`.limbs.len < a.limbs.len + b.limbs.len
  ## The result will be truncated, i.e. it will be
  ## a * b (mod (2^WordBitWidth)^r.limbs.len)
  ##
  ## Assumes r doesn't alias a or b

  result = newStmtList()

  var ctx = init(Assembler_x86, BaseType)
  let
    r = asmArray(r_PIR, rLen, PointerInReg, asmInputOutputEarlyClobber, memIndirect = memWrite) # MemOffsettable is the better constraint but compilers say it is impossible. Use early clobber to ensure it is not affected by constant propagation at slight pessimization (reloading it).
    a = asmArray(a_MEM, aLen, MemOffsettable, asmInput)
    b = asmArray(b_MEM, bLen, MemOffsettable, asmInput)
  ...

and also here https://github.com/mratsim/Arraymancer/blob/2535236/src/arraymancer/tensor/accessors_macros_read.nim#L20-L21 but then I remember long fights for types in macro: nim-lang/RFCs#44

@metagn
Copy link
Collaborator

metagn commented Jan 13, 2025

The current compiler should support generic macros but only for overloading purposes i.e. in the signature, and static parameters won't work when passed to other static parameters, but I didn't consider that they work as "runtime" values. The length parameter in asmArray is a runtime parameter. This errors for example, but not if foo takes an int argument:

proc foo(x: static int) = echo x

macro bar(x: static int) =
  foo(x) # type mismatch: got int
  
bar(123)

That being said, both generic overloading and statics as runtime values working mean that the code in the issue should work, so this probably is specific to getAst. It doesn't seem to perform overload resolution at all or check the type of the arguments so N is never inferred. At least ccopy2[N](a1, b1, ctl1) should work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants