Nim icon indicating copy to clipboard operation
Nim copied to clipboard

template lookup fails with nested generic types

Open arnetheduck opened this issue 7 years ago • 10 comments

this should compile:

type
  X[T] = object
    inner: T

template nest(t: int): untyped = 42
template nest(t: X): untyped = nest(t.inner)

# uncomment to make one level of nesting work
# template nest(t: X[X]): untyped = nest(t.inner)

var tmp: X[X[int]]

echo nest(tmp)

instead, it gives:

nim c nested
Hint: used config file '/home/arnetheduck/status/Nim/config/nim.cfg' [Conf]
Hint: system [Processing]
Hint: nested [Processing]
nested.nim(13, 10) Error: type mismatch: got <X[system.int]>
but expected one of: 
template nest(t: int): untyped

expression: nest(tmp.inner)

 nim --version
Nim Compiler Version 0.19.0 [Linux: amd64]
Compiled at 2018-09-26
Copyright (c) 2006-2018 by Andreas Rumpf

git hash: 4b2f0035007d4060dd16279c8c5e49c0cfb3b8f7
active boot switches: -d:release

arnetheduck avatar Oct 24 '18 16:10 arnetheduck

I have a workaround with macros:


type
  X[T] = object
    inner: T

import macros

macro nest(arg: typed): untyped =
  if arg.getTypeInst == bindSym"int":
    result = newLit(42)
  else:
    result = quote do:
      nest(`arg`.inner)

var tmp: X[X[int]]

echo nest(tmp)

It seems the template doesn't take itself into consideration for symbol lookup. But that macro above does technically the same thing.

krux02 avatar Dec 04 '18 14:12 krux02

yeah, macros obfuscate the intent of the code though - it can also be worked around by adding explicitly instantiated overloads, but neither is really a general / satisfactory solution

arnetheduck avatar Dec 04 '18 14:12 arnetheduck

The macro solution is a general solution. It is even more general than the template solution. But I agree that it would be better if overloading would be nicer. This workaround is more scaleable than the explicit overloads.

krux02 avatar Dec 04 '18 14:12 krux02

ah, sorry, something I failed to mention is that nest is an extension point for an api, so it might come from any module, really, meaning we can't implement the macro in the suggested way - the bug was discovered while trying to move away from a macro to use a more natural feature of the language :)

arnetheduck avatar Dec 04 '18 15:12 arnetheduck

Adding a mixin works. Otherwise, since there is only one previous definition of nest, the call gets bound to a closed symbol.

type
  X[T] = object
    inner: T

template nest(t: int): untyped = 42
template nest(t: X): untyped =
  mixin nest
  nest(t.inner)

var tmp: X[X[int]]

echo nest(tmp)

jcosborn avatar Jan 04 '19 03:01 jcosborn

@jcosborn perfect - works and expresses the intent clearly, thanks!

so.. is this just a poor error message / should the mixin be necessary for recursive calls?

arnetheduck avatar Jan 07 '19 18:01 arnetheduck

The error message is correct, but if one isn't aware of the rule, it can be confusing. Adding a suggestion to try mixin if the symbol is closed could be useful.

I don't know if having the routine name symbol visible in the routine body is feasible, but it does seem like it would be useful.

jcosborn avatar Jan 08 '19 03:01 jcosborn

This issue has been automatically marked as stale because it has not had recent activity. If you think it is still a valid issue, write a comment below; otherwise it will be closed. Thank you for your contributions.

stale[bot] avatar Aug 04 '20 08:08 stale[bot]

import macros

macro typedTree(foo: typed) =
  echo foo.treeRepr
  foo

type X[T] = object
  inner: T

template nest(t: int): untyped = 42
typedTree:
  template nest(t: X): untyped = nest(t.inner)

Gives:

StmtList
  TemplateDef
    Sym "nest"
    Empty
    GenericParams
      Sym "X"
    FormalParams
      Sym "untyped"
      IdentDefs
        Sym "t"
        Sym "X"
        Empty
    Empty
    Bracket
      Empty
      Empty
    StmtList
      Call
        Sym "nest"
        DotExpr
          Sym "t"
          Ident "inner"

Important part being Sym "nest". Template doesn't notice itself when getting a sym choice for nest. Maybe related: #12012

metagn avatar Aug 23 '23 01:08 metagn

Also mixin nest is a workaround

metagn avatar Jan 09 '24 17:01 metagn