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

`type Bar = (int, seq, array, tuple, set)` should give CT error #14800

Open timotheecour opened 4 years ago

timotheecour commented 4 years ago

type Bar = (int, seq, array, tuple, set) should give CT error

(similar to recent bug fixes but this one is still not fixed)

Example

when true:
  type Bar = (int, seq, array, tuple, set) # should probably be disallowed because all elements after position 1 are not concrete types
  echo Bar.sizeof # Error: internal error: getTypeDescAux(tyGenericParam)

Current Output

Error: internal error: getTypeDescAux(tyGenericParam)

Expected Output

this should give CT error but is currently accepted

type Bar = (int, seq, array, tuple, set)

Additional Information

metagn commented 1 year ago

It should compile, it's a typeclass in theory. Though it currently crashes as one.

type Bar = (int, seq, array, tuple, set)

echo (int, seq[int], array[1, int], (int,), set[int8]) is Bar # invalid kind for lastOrd(tyGenericParam), but should be true
metagn commented 1 year ago

The specific error here is caused by array, seq and set compile and tuple gives another manual error

template tupleTypeClass(base, concrete) =
  type Bar = tuple[a: base]
  echo tuple[a: concrete] is Bar

tupleTypeClass seq, seq[int] # compiles, true
tupleTypeClass set, set[int8] # compiles, true
tupleTypeClass array, array[2, int] # internal error: invalid kind for lastOrd(tyGenericParam)
tupleTypeClass tuple, (int, int) # Error: 'tuple' is not a concrete type

It's actually not recognized as a typeclass in the cases where it compiles with seq and set

type Bar = tuple[a: seq]

proc foo(x: Bar) =
  echo x # type mismatch
  # discard instead gives "invalid type T in this context proc (x: Bar) ..."
  # same if we just write tuple[a: seq] instead of Bar

foo((a: @[1, 2]))

So either we don't allow typeclass tuple types (and point this out in the documentation), or we lift these to typeclasses.

Araq commented 1 year ago

... or we lift these to typeclasses.

Seems better than a special case in the manual that reflects an oversight in the compiler.

metagn commented 1 year ago

Apparently in general concrete types lifting to typeclasses gives different results.

type Foo = array[2, tuple]

echo array[2, (int, int)] is Foo # true
echo array[2, int] is Foo # false
proc foo(x: Foo) = echo x
foo({1: 2, 3: 4}) # [(1, 2), (3, 4)]

var x: Foo # invalid type: ':anon:type' in this context: 'Foo' for var
type Foo = array[2, array]
# internal error: invalid kind for lastOrd(tyGenericParam)

The manual error for tuple is caused by an explicit check in semstmts for just objects and tuples:

https://github.com/nim-lang/Nim/blob/21d941c16a84daa855870717f064802b052d6792/compiler/semstmts.nim#L1557-L1558

For objects it makes sense, they should never be typeclasses (same for any nominal type). But for other types this check could be used to mark the entire type as meta to error when we try to use it as a concrete type.

The manual says this:

A type class is a special pseudo-type that can be used to match against types in the context of overload resolution or the is operator.

Type classes can be combined using the standard boolean operators to form more complex type classes

Nothing about combining type classes with concrete types. So we don't really have an obligation to support this, but also the compiler happens to fundamentally support it in both use cases, overload resolution and the is operator.

In any case the compiler crash with array should be addressed.