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

Callback with generics can crash compiler #22921

Open ggb-sw opened 1 year ago

ggb-sw commented 1 year ago

Description

Probably asking the compiler to use a generic as a callback is understandably stressing the compiler out a bit, and maybe it is simply more than the language is capable of, but having the compiler crash is probably not the most informative way of telling the user he should not be trying to do it.

#!/usr/bin/env -S nim r
## :File: test1.nim
##

import sugar

type
  AType = (int | char)

func tfunc(val: AType) : bool =
  let i = int(val)
  i mod 5 == 0

type
  func_proto* = ((AType) {.noSideEffect.} -> bool)

func test(val: AType, fun:func_proto) : bool =
  fun(val)

# The following line (if uncommented)
# creates compile error :
#    Error: 'tfunc' doesn't have a concrete type, due to unspecified generic parameters.
# echo test(25, tfunc)

# The following line (if uncommented)
# Causes compiler crash with:
#    Error: internal error: getTypeDescAux(tyOr)
#    No stack traceback available
#    To create a stacktrace, rerun compilation with './koch temp r <file>', see https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler for details
# echo test(25, tfunc[int])

Nim Version

Nim Compiler Version 2.0.0 [Linux: amd64] Compiled at 2023-08-01 Copyright (c) 2006-2023 by Andreas Rumpf

git hash: a488067a4130f029000be4550a0fb1b39e0e9e7c active boot switches: -d:release

Current Output

No response

Expected Output

No response

Possible Solution

No response

Additional Information

No response

metagn commented 1 year ago

The implicit generic from the func_proto proc type is likely not lifted to the proc it's used for a parameter of (but I might be wrong).

proc tfunc(val: int) : bool =
  let i = int(val)
  i mod 5 == 0

proc test(val2: int | char, fun: proc (_: int | char): bool) : bool =
  fun(val2)

echo test(123, tfunc)
Error: internal error: getTypeDescAux(tyOr)

As another example of an implicit generic type nested in a concrete type (ignoring proc type generic parameter list association weirdness), this also doesn't work but gives a type match error:

type Foo[T] = object
  x: T

proc foo(x: Foo[int | char]) = echo x

foo(Foo[int](x: 123))
(6, 4) Error: type mismatch
Expression: foo(Foo[int](x: 123))
  [1] Foo[int](x: 123): Foo[system.int]

Expected one of (first mismatch at [position]):
[1] proc foo(x: Foo[int | char])

Maybe we could always treat Foo[int | char], proc (x: int | char) etc as invalid?