Description
Scala 2-style implicit conversions that take implicit parameters (let’s call them “conditional conversions”) don’t suggest imports if their implicit parameter can’t be found. Instead, a “value bar is not a member of Foo” error is reported.
Minimized code
trait Foo[A]
class FooOps[A](self: A)(implicit foo: Foo[A]) {
def bar: Unit = ()
}
object Implicits {
implicit def fooOps[A](a: A)(implicit foo: Foo[A]): FooOps[A] = new FooOps(a)
implicit def fooInt: Foo[Int] = new Foo[Int] {}
}
object Usage {
import Implicits.fooOps
42.bar
}
Output
[error] -- [E008] Not Found Error:
[error] 44 | 42.bar
[error] | ^^^^^^
[error] | value bar is not a member of Int
Expectation
We should suggest importing Implicits.fooInt
.
Discussion
Note that if we omit the import Implicits.fooOps
clause, we get the following error message:
[error] -- [E008] Not Found Error:
[error] 44 | 42.bar
[error] | ^^^^^^
[error] |value bar is not a member of Int, but could be made available as an extension method.
[error] |
[error] |The following import might make progress towards fixing the problem:
[error] |
[error] | import Implicits.fooOps
However, following the import suggestion leads to the error reported above!
It is worth noting that a similar example but using extension methods instead of conditional implicit conversions provides a better developer experience:
trait Foo[A] {
def (self: A).bar: Unit = ()
}
object Implicits {
implicit def fooInt: Foo[Int] = new Foo[Int] {}
}
object Usage {
42.bar
}
Gives the following compilation error:
[error] -- [E008] Not Found Error:
[error] 55 | 42.bar
[error] | ^^^^^^
[error] |value bar is not a member of Int, but could be made available as an extension method.
[error] |
[error] |The following import might fix the problem:
[error] |
[error] | import Implicits.fooInt
And adding the suggested import fixes the compilation error.
Unfortunately, many Scala libraries (e.g., cats) still use conditional implicit conversions. I wish they could migrate to extension methods but this is not realistic because they couldn’t be called as methods from Scala 2 codebases.