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

instantiationInfo-like for plain proc #11689

Open
mratsim opened this issue Jul 8, 2019 · 1 comment
Open

instantiationInfo-like for plain proc #11689

mratsim opened this issue Jul 8, 2019 · 1 comment
Labels

Comments

@mratsim
Copy link
Collaborator

mratsim commented Jul 8, 2019

Related to #7406, #6469

instantiationInfo works for generic proc, templates and macro but not for normal proc:

type
  Foo = object
    lineinfo: tuple[filename: string, line, column: int]

proc initFooProc(x: int): Foo =
  Foo(lineinfo: instantiationInfo())

proc initFooGenericProc[T](x: int): Foo =
  Foo(lineinfo: instantiationInfo())

template initFooTemplate(x: int): Foo =
  Foo(lineinfo: instantiationInfo())

block:
  let p = initFooProc(1)
  let gp = initFooGenericProc[int](2)
  let t = initFooTemplate(3)

  echo p.lineinfo  # (filename: "???", line: 0, column: -1)
  echo gp.lineinfo # (filename: "inst.nim", line: 16, column: 29)
  echo t.lineinfo  # (filename: "inst.nim", line: 17, column: 25)

It would be useful to have a callInfo magic that gives the same detail for logging or error reporting purpose. This can also include the proc name (as requested in #7406 and #8212).

The Nim documentation encourages using the least powerful construct fit for purpose between proc/template/macro. This feature will make it easier to use proc when a library grows large enough to require call site information for error or logging purposes.

@mratsim mratsim added the Feature label Jul 8, 2019
mratsim added a commit to mratsim/laser that referenced this issue Jul 8, 2019
@timotheecour
Copy link
Member

timotheecour commented Jul 11, 2019

instantiationInfo works for generic proc,

while it "works", it doesn't work the way you're implying, eg:

    let gp1 = initFooGenericProc[int](2) # line 100
    let gp2 = initFooGenericProc[float](2)
    let gp3 = initFooGenericProc[int](2)

you'll get:

line 100
line 101
line 100 # reused!

which makes sense.

Since a proc (non generic, or a generic proc with a given instantiation parameters, eg int in above example) is only evaluated once, theres' no way to make it work the way you wrote it with instantiationInfo called inside the proc body.

The only way to make this work for generics and procs (without introducing a wrapper template as @zah was suggesting here #7406 (comment)) is by making optional arguments instantiated at caller site instead of callee site, as I was mentioning in #7406 (comment)

# maybe via a pragma, eg:
proc initFooProc(x: int, info = instantiationInfo() {.caller.}): Foo =
  Foo(lineinfo: info)

This is the approach used in D with __FILE_PATH__.

callsiteMagic

if @zah 's suggestion from #7406 (comment) isn't enough, you can automate it via a macro callsiteMagic:

proc initFooProc(x: int, info: InstantiationInfo()): Foo {.callsiteMagic.}
  Foo(lineinfo: info)

# with:
macro callsiteMagic(fun: untyped) =
  # creates wrapper template with same name and arguments as `fun`; for above example it'd be:
  # template initFooProc(x: int): untyped = initFooProc(x, instantiationInfo())

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

No branches or pull requests

2 participants