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

Feature request for a NimNode to typedesc conversion proc in macros #6785

Closed
bluenote10 opened this issue Nov 20, 2017 · 10 comments
Closed

Feature request for a NimNode to typedesc conversion proc in macros #6785

bluenote10 opened this issue Nov 20, 2017 · 10 comments

Comments

@bluenote10
Copy link
Contributor

Currently, macros.nim does not offer a way to convert a NimNode (obtained from getType on a typed expression) into the corresponding typedesc:

import macros

proc f(T: typedesc[SomeInteger]) =
  echo "called f with some integer"

proc f(T: typedesc[string]) =
  echo "called f with string"

macro aMacro(x: typed) =
  let typeNode = x.getType()
  # Call f at compile time is not possible because
  # typeNode can't be converted to typedesc.
  f(typeNode)

aMacro(1)
aMacro("string")

Error:

test.nim(13, 4) Error: type mismatch: got (NimNode)
but expected one of: 
proc f(T: typedesc[SomeInteger])
proc f(T: typedesc[string])

Note that there is a workaround: Doubling the argument of the macro into aMacro(x: type, typedescOfX: typedesc), and one could write a wrapper macro that takes a typed expression x and generates the AST aMacro(x, type(x)).

@jangko
Copy link
Contributor

jangko commented May 30, 2019

similar with above issue, inside macro/compile time proc we cannot convert NimNode back into compile-time-value without workaround. An intLit or strLit of course can use intVal and strVal, but something like enum need few more lines to convert it back into compile-time-value.

for example:

type
  Fruit = enum
    apple
    banana
    orange
    
macro hello(x: static[Fruit]) =
  echo x  # here x is a compile time value

macro foo(x: typed) =
  # x is a symbol
  echo "possible but not simple"

macro bar(x: untyped) =
  # x is a list of idents
  echo "possible but not simple"

hello(apple) # ok

foo(apple)

bar:
  apple
  banana
  orange

we have static param and typedesc param for macro, we can convert NimNode into runtime literal.
additional compiler magic to convert NimNode into compile-time-value and compile-time-type-literal will be handy.

@krux02
Copy link
Contributor

krux02 commented Jun 5, 2019

The issue as it is proposed cannot work. Let's assume there would be a typedescVal, it would return a typedesc without a generic parameter. So you would not be able to call f on it. Here is an example:

proc f(T: typedesc[SomeInteger]) =
  echo "called f with some integer"

proc f(T: typedesc[string]) =
  echo "called f with string"

static:
  let xxx = [int, string]  # xxx is now such a typedesc
  echo f(xxx[0])

nimout:

scratch.nim(51, 9) Error: type mismatch: got <typedesc>
but expected one of: 
proc f(T: typedesc[SomeInteger])
proc f(T: typedesc[string])

You have to generate the call to f to make it work

import macros

proc f(T: typedesc[SomeInteger]) =
  echo "called f with some integer"

proc f(T: typedesc[string]) =
  echo "called f with string"

proc f(arg: NimNode) =
  let someInt = bindSym"SomeInteger"
  echo someInt.getImpl.treeREpr
  #echo arg.treeRepr

macro aMacro(x: typed) =
  result = quote do:
    f(typeof(`x`))

aMacro(1)        # called f with some integer
aMacro("string") # called f with string

The overall conclusion is, typedesc is misdesigned. The goal is to use less of it, not more.

So I have to reject this proposal as it does not solve anything.

@jangko I just made a PR, so that you can get enums values from symbols easily. I hope Fruit(n.intVal) isn't too complicated. #11403

@krux02 krux02 closed this as completed Jun 5, 2019
@bluenote10
Copy link
Contributor Author

I don't get what your example has to do with the original example. In the original example all necessary information should be in the NimNode.

@krux02
Copy link
Contributor

krux02 commented Jun 5, 2019

Please elaborate on what you don't understand. I went into quite some detail about why your proposal can't work. typedesc is very confusing.

@jangko
Copy link
Contributor

jangko commented Jun 5, 2019

@krux02 thank you for the enum magic, that would be very useful.

@bluenote10 : I think from @krux02 example, he want to says typedesc typedesc and possibly another typedesc typedesc typedesc ... is really confusing.

static:
  let xxx = [int, string]  # xxx is now such a typedesc
  echo f(xxx[0])

but your example also a bit confusing, I think if it modified a bit, it would make your intention clearer.
perhaps what you want is something like this:

import macros

proc f(T: typedesc[SomeInteger]) =
  echo "called f with some integer"

proc f(T: typedesc[string]) =
  echo "called f with string"

macro aMacro(x: typed) =
  let typeNode   = x.getType()
  const T = typeMagic(typeNode)  # `typeMagic` is not available in macros module
  f(T)

aMacro(1)
aMacro("string")

@zah
Copy link
Member

zah commented Jun 5, 2019

It's certainly possible to define semantics that will make @krux02's example work.
You can treat the overloaded typedesc procs as methods using dynamic dispatch based on the "concrete" type stored in the "abstract" typedesc instance variable.

@bluenote10
Copy link
Contributor Author

@krux02 The use case is to call f at compile time. Within the macro the type of x is fully determined because it is typed. If the macro is called with 1 the type can be inferred to int and thus all information to call f(int) is available. Your snippet is an example of typedescs losing their generic argument -- I don't see the connection.

Your work-around doesn't address the use case, which is to call f within the macro statically, not returning an AST of f calls.

@krux02
Copy link
Contributor

krux02 commented Jun 6, 2019

It's certainly possible to define semantics that will make @krux02's example work. You can treat the overloaded typedesc procs as methods using dynamic dispatch based on the "concrete" type stored in the "abstract" typedesc instance variable.

Sorry, but no. procs remain procs with static dispatich. And methods remain methods with dynamic dispatch. This is out of discussion.

@mratsim
Copy link
Collaborator

mratsim commented Jul 7, 2019

If typedesc is misdesigned that's an argument to overhaul typedesc, not to close this reasonable feature in my opinion.

Currently I can't use the sameType macro from a IdentDef to check if sameType(x, bindSym"seq") with x being nnkBracketExpr(ident"seq", ident"int") because I have no way to convert back x to a typed node after parsing it from a proc definition.

I.e. another case of nim-lang/RFCs#44

mratsim added a commit to mratsim/laser that referenced this issue Jul 7, 2019
mratsim added a commit to mratsim/constantine that referenced this issue Oct 10, 2020
- includes type system workaround: generic sandwich nim-lang/Nim#11225
- converting NimNode to typedesc: nim-lang/Nim#6785
mratsim added a commit to mratsim/constantine that referenced this issue Oct 10, 2020
* Implement a Sage codegenerator for frobenius constants

* Sage codegen for pairings

* Autogen of endomorphism acceleration constants

* The autogen fixed a copy-paste bug in lattice decomposition. We can use conditional negation now and save an add+dbl in scalar mul

* small fixes

* sage code for square root bls12-377 is not old

* readme updates

* Provide test suggestions for derive_frobenius

* indentation + add equation form to sage

* Sage test vector generator

* Use the json vectors
- includes type system workaround: generic sandwich nim-lang/Nim#11225
- converting NimNode to typedesc: nim-lang/Nim#6785

* Delete old sage code

* Install nim-serialization and nim-json-serialization in CI

* CI nimble install force yes
@mratsim
Copy link
Collaborator

mratsim commented Feb 14, 2022

Another: https://forum.nim-lang.org/t/8913

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

6 participants