Skip to content

Nim Compiler Cannot Resolve Generic Types in Some Cases #21168

Open
@Capital-EX

Description

@Capital-EX

Description

While experimenting with the idea of combinators, I discovered the following bug with the resolution of generic types:

import sugar

proc bi[A, B](xy: (A, A),
              f: (A) -> B): (B, B) =
  (f(xy[0]), f(xy[1]))

func bi[A, B, C](x: A, 
                 f: (A) -> B, 
                 g: (A) -> C): (B, C) = 
  (f(x), g(x))

echo (10, 20).bi((x) => x * x) # Errors with type mismatch

It appears that the Nim compiler cannot resolve which implementation of bi to use nor the type of x. It seems to pick bi[A, B, C] even though the number of arguments does not match. However, if it is actually choosing bi[A, B] then it is inferring the type of A incorrectly. Additionally, the error message does not inform the user that the resolution of bi is ambiguous.

This ambiguity can be resolve by changing the last line to the following:

echo (10, 20).bi((x: int) => x * x)

This change forces the Nim compiler to resolve bi as bi[A, B]. However, this solution was not clear from the error message.

Nim Version

Nim Compiler Version 1.6.10 [Linux: amd64]

Current Output

main.nim(13, 27) Error: type mismatch: got <(int, int), (int, int)>
but expected one of:
func `*`[T](x, y: set[T]): set[T]
  first type mismatch at position: 1
  required type for x: set[T]
  but expression 'x' is of type: (int, int)
proc `*`(x, y: float): float
  first type mismatch at position: 1
  required type for x: float
  but expression 'x' is of type: (int, int)
proc `*`(x, y: float32): float32
  first type mismatch at position: 1
  required type for x: float32
  but expression 'x' is of type: (int, int)
proc `*`(x, y: int): int
  first type mismatch at position: 1
  required type for x: int
  but expression 'x' is of type: (int, int)
proc `*`(x, y: int16): int16
  first type mismatch at position: 1
  required type for x: int16
  but expression 'x' is of type: (int, int)
proc `*`(x, y: int32): int32
  first type mismatch at position: 1
  required type for x: int32
  but expression 'x' is of type: (int, int)
proc `*`(x, y: int64): int64
  first type mismatch at position: 1
  required type for x: int64
  but expression 'x' is of type: (int, int)
proc `*`(x, y: int8): int8
  first type mismatch at position: 1
  required type for x: int8
  but expression 'x' is of type: (int, int)
proc `*`(x, y: uint): uint
  first type mismatch at position: 1
  required type for x: uint
  but expression 'x' is of type: (int, int)
proc `*`(x, y: uint16): uint16
  first type mismatch at position: 1
  required type for x: uint16
  but expression 'x' is of type: (int, int)
proc `*`(x, y: uint32): uint32
  first type mismatch at position: 1
  required type for x: uint32
  but expression 'x' is of type: (int, int)
proc `*`(x, y: uint64): uint64
  first type mismatch at position: 1
  required type for x: uint64
  but expression 'x' is of type: (int, int)
proc `*`(x, y: uint8): uint8
  first type mismatch at position: 1
  required type for x: uint8
  but expression 'x' is of type: (int, int)

expression: x * x

Expected Output

No response

Possible Solution

  • Improved error messaging in this edge case.
  • Giving the compiler the ability to resolve the types here.

Additional Information

It is worth noting that a language such as Kotlin can resolve similar constructions:

fun <A, B> bi(pair: Pair<A, A>, f: (A) -> B): Pair<B, B> {
    return Pair(f(pair.first), f(pair.second))
}

fun <A, B, C> bi(x: A, f: (A) -> B, g: (A) -> C): Pair<B, C> {
    return Pair(f(x), g(x))
}

fun main() {
    println(bi(Pair(10, 20), { x -> x * x }))
    println("Hello, world!!!")
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions