effekt-lang / effekt

A research language with effect handlers and lightweight effect polymorphism

Home Page:https://effekt-lang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Confusing error message for different types with same name

jiribenes opened this issue · comments

Trying to write a sort that works on the first element of a tuple:

import immutable/list

def comparePairsByFirst[A, B](x: Tuple2[A, B], y: Tuple2[A, B]){ compare: (A, A) => Boolean }: Boolean = {
    val (a1, b1) = x
    val (a2, b2) = y
    compare(a1, a2)
}

def sortOnFst[Int, B](lst: List[Tuple2[Int, B]]): List[Tuple2[Int, B]] = {
    lst.sortBy { (p1, p2) => 
      comparePairsByFirst(p1, p2) { 
        (a, b) => a < b 
      } 
    }
}

This is reproducible both on the website and on current master.

I got the following error message:

Cannot typecheck call.
There are multiple overloads, which all fail to check:

Possible overload: effekt.infixLt of type (Int, Int) => Boolean
  Expected Int but got Int.
  Expected Int but got Int.

Possible overload: effekt.infixLt$1 of type (Double, Double) => Boolean
  Expected Double but got Int.
  Expected Double but got Int.

Possible overload: effekt.infixLt$2 of type (String, String) => Boolean
  Expected String but got Int.
  Expected String but got Int.

Specifically, the very first part seems wrong:

Possible overload: effekt.infixLt of type (Int, Int) => Boolean
  Expected Int but got Int.
  Expected Int but got Int.

This overload looks like it should work in my case (I'm comparing two Ints), but it gets refused for some mysterious reason.

Note: type annotations don't help:

def sortFst[Int, B](lst: List[Tuple2[Int, B]]): List[Tuple2[Int, B]] = {
    lst.sortBy { (p1: Tuple2[Int, B], p2: Tuple2[Int, B]) => 
      comparePairsByFirst(p1, p2) { 
        (a: Int, b: Int) => a < b 
      } 
    }
}

@b-studios helpfully told me that the problem is here:

def sortFst[Int, B]

^ we're binding Int as a type variable, so the error should actually say something like:

Possible overload: effekt.infixLt of type (effekt/Int, effekt/Int) => Boolean
  Expected effekt/Int but got main/Int.
  Expected effekt/Int but got main/Int.

We could check whether the two types print to the same and then use the fully qualified name.

This should be (partially) addressed by #368. @jiribenes do you think this issue here is still relevant?

It's better since now there's an additional message:

Type parameter Int shadows outer definition of Int

which is already helpful.

But since we have namespaces, it would be nice to say something like:

Possible overload: effekt::infixLt of type (Int, Int) => Boolean
  Expected effekt::Int but got main::Int.
  Expected effekt::Int but got main::Int.
           ^^^^^^^^            ^^^^^^

Some logic like "If the types are named the same, print their whole qualified path". :)