scala3 icon indicating copy to clipboard operation
scala3 copied to clipboard

Confusing error message when type arguments are supplied to a higher kinded type

Open OndrejSpanel opened this issue 1 year ago • 1 comments

Compiler version

3.3.3 3.4.1

Minimized example

The example is minimized from a real life example using borer library.

The same error can be produced by using given instead of implicit, as shown in the commented out code.

object Main {

  trait Wrap[X] {
    def write(value: X): Unit
  }

  implicit def forMap[A, B, M[X, Y] <: Map[X, Y]]: Wrap[M[A, B]] = ???

  //given givenForMap[A: Encoder, B: Encoder, M[X, Y] <: Map[X, Y]]: Wrap[M[A, B]] = ???

  def main(args: Array[String]): Unit = {
    val value = Map.empty[String, Int]

    //val g = givenForMap[String, Int, Map[String, Int]]
    //g.write(value)

    val m = forMap[String, Int, Map[String, Int]]
    m.write(value)
  }
}

Output Error/Warning message

[error] -- [E007] Type Mismatch Error: C:\Dev\scala3compat\src\main\scala\Main.scala:18:12
[error] 18 |    m.write(value)
[error]    |            ^^^^^
[error]    |            Found:    (value : Map[String, Int])
[error]    |            Required: Map[String, Int][String, Int]
[error]    |

Why this Error/Warning was not helpful

The type which is written as required is impossible to create.

When I remove the line m.write(value), much more sensible error is reported:

[error] 17 |    val m = forMap[String, Int, Map[String, Int]]
[error]    |                                ^
[error]    |      Type argument Map[String, Int] does not conform to upper bound Map

When compiling with Scala 2, the error is even more sensible:

[error] C:\Dev\scala3compat\src\main\scala\Main.scala:17:33: Map[String,Int] takes no type parameters, expected: 2
[error]     val m = forMap[String, Int, Map[String, Int]]

Suggested improvement

The error should be diagnosed differently, so that it does not print an impossible type as required. Scala 2 seems to be more robust by not allowing to pass type arguments in a position where they are not expected.

OndrejSpanel avatar Apr 08 '24 14:04 OndrejSpanel

I've just run into

def foo[F[_]](a: F[Int]): Unit = ()
foo[Null](null)
Error message
Found:    Null
Required: Null[Int]
Note that implicit conversions were not tried because the result of an implicit conversion
must be more specific than Null[Int]

Explanation
===========

Tree: null
I tried to show that
  Null
conforms to
  Null[Int]
but none of the attempts shown below succeeded:

  ==> Null  <:  Null[Int]  = false

The tests were made under a constraint with:
 uninstantiated variables: T, T
 constrained types: [T](x: T): T, [T](x: T): T
 bounds:
     T
     T
 ordering:
 co-deps:
 contra-deps:

as well as

def foo[F[_]](a: F[Int]): Unit = ()
foo[Null]
Error message
Found:    (a : Null[Int])
Required: Null[Int]
Note that implicit conversions were not tried because the result of an implicit conversion
must be more specific than Null[Int]

Explanation
===========

Tree: a
I tried to show that
  (a : Null[Int])
conforms to
  Null[Int]
but none of the attempts shown below succeeded:

  ==> (a : Null[Int])  <:  Null[Int]  = false

The tests were made under a constraint with:
 uninstantiated variables: T, T
 constrained types: [T](x: T): T, [T](x: T): T
 bounds:
     T
     T
 ordering:
 co-deps:
 contra-deps:

which I believe is a further minimization of this issue. Both 3.3.4 and 3.5.1.

s5bug avatar Oct 16 '24 15:10 s5bug