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.55k stars 1.47k forks source link

type mismatch, expected none on type parameter in template #13965

Open arnetheduck opened 4 years ago

arnetheduck commented 4 years ago

Example

type
  Obj = object
    v: int

  HasFrm = object
    v: int

template frm(T: type HasFrm, o: Obj): T = T(v: o.v)

template to*(v: auto, T: type): T =
  mixin frm
  frm(T, v)

# works:
# template to*(v: auto, T: type HasFrm): T =
#  mixin frm
#  frm(T, v)

let
  o = Obj(v: 42)
  hft = o.to(HasFrm)

Current Output

/home/arnetheduck/tmp/test.nim(21, 10) Error: type mismatch: got <HasFrm> but expected 'None'
[arnetheduck@tempus tmp]$ nim -v
Nim Compiler Version 1.2.0 [Linux: amd64]
Compiled at 2020-04-03
Copyright (c) 2006-2020 by Andreas Rumpf

active boot switches: -d:release
metagn commented 1 year ago

This works:

type
  Obj = object
    v: int

  HasFrm = object
    v: int

template frm[T: HasFrm](Te: typedesc[T], o: Obj): T = Te(v: o.v)

template to*[T](v: auto, Te: typedesc[T]): T =
  mixin frm
  frm(Te, v)

let
  o = Obj(v: 42)
  hft = o.to(HasFrm)

typedesc[T] and type[T] work but type T breaks. This is one bug.

The bug in the original example has to do with the fact that we are using the template parameter T in the signature (which has constraint None, and so this is what the return type is inferred as early on). Normally procs would bind the type of T to the implicit generic it's attached to which would give the correct return type on instantiation, but I'm not sure if implicit generics exist in templates. If they don't, we can force the use of generics here and disallow using template parameters in the signature, or at least suggest using generics.

See also #7160