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

Converters found after a match not typechecked #13061

Open deech opened 4 years ago

deech commented 4 years ago

The second converter is not typechecked

Example

type
  A = distinct int

# If two converters do the same thing after a match is found the rest are not typechecked
converter toA(a:A):int = (int)a
converter anotherToA(a:A):int = "lol"

# If the wrong one comes first it is typechecked and throws a compiler error
# converter anotherToA(a:A):int = "lol"
# converter toA(a:A):int = (int)a

Current Output

Successful compilation

Expected Output

Error: type mismatch: got <string> but expected 'int'

Nim Version

$ nim -v
Nim Compiler Version 1.0.4
metagn commented 4 years ago

Can't reproduce, this fails to compile on 1.0.4. Unrelated, but (int)a only works because it is equivalent to (int) a which is equivalent to (int)(a), and should be int a, int(a) or a.int to avoid confusion.

deech commented 4 years ago

Yes you're right, I tried to a provide a simple example using base types, but I just tested and this does compile when it shouldn't:

type
  A[T] = distinct seq[T]

converter fromA[T](a:A[T]):seq[T] = seq a 
converter fromA1[T](a:A[T]):seq[T] = "lol"
metagn commented 4 years ago

That is expected. Instances of fromA1[T] are not semantically checked until it's instantiated by non-generic code, fulfilling the argument T. If you switch the order of the converters, it fails because the second converter calls the first converter. An example like this also compiles:

type
  A[T] = distinct seq[T]

proc fromA1[T](a:A[T]): seq[T] = "lol"

So does:

proc fromA1[T](a:seq[T]): seq[T] = "lol"

If you're developing a package and encountered this issue I would recommend writing tests or trying to compile your own application that uses it to check. Compile time semantic checks for behaviour like this doesn't cover all the needs of first party libraries and packages, but it does cover the needs of applications.

deech commented 4 years ago

But in this case at least the first converter must get instantiated because it outputs @[2,3,4]:

import sequtils

type
  A[T] = distinct seq[T]

converter fromA[T](a:A[T]):seq[T] = seq[T](a) 
converter fromA1[T](a:A[T]):seq[T] = "lol"

echo A(@[1,2,3]).mapIt(it+1)
metagn commented 4 years ago

The second converter is defined after the first one, meaning fromA doesn't use fromA1 if defined before. It just uses the normal seq[T]() converter. It makes sense that fromA1 isn't instantiated in that case but fromA is. Still, a wild situation, and I have no idea what would happen if you turned on reordering.