Why does scalac seem to expand implicits too far?

Viewed 25

I am trying to diagnose a compiler error which is caused by diverging implicit expansion errors.

Here is what I am seeing:

❯ scala
Welcome to Scala 2.13.1 (OpenJDK 64-Bit Server VM, Java 1.8.0_252).
Type in expressions for evaluation. Or try :help.

scala> :settings -Xlog-implicits

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait Invariant[A]
trait Covariant[+A]
trait Foo

implicit def invariantTuple1[T1: Invariant]: Invariant[Tuple1[T1]] = ???

implicit def invariantFoo: Invariant[Foo] = ???

def a = implicitly[Invariant[Foo]]

implicit def covariant[A: Invariant]: Covariant[A] = ???

def b = implicitly[Covariant[Foo]]

// Exiting paste mode, now interpreting.


def b = implicitly[Covariant[Foo]]
                  ^
<pastie>:13: invariantTuple1 is not a valid implicit value for Invariant[T1] because:
hasMatchingSymbol reported error: diverging implicit expansion for type Invariant[T1]
starting with method invariantFoo

def b = implicitly[Covariant[Foo]]
                  ^
<pastie>:13: invariantFoo is not a valid implicit value for Invariant[T1] because:
diverging implicit expansion for type Invariant[T1]
starting with method invariantTuple1

def b = implicitly[Covariant[Foo]]
                  ^

(remaining output elided for clarity)

I want to know why specifically does this the compiler output these particular diverging implicit expansion messages?

Take this one first:

invariantTuple1 is not a valid implicit value for Invariant[T1] because:
hasMatchingSymbol reported error: diverging implicit expansion for type Invariant[T1]
starting with method invariantFoo

What does the "starting with method invariantFoo" mean here?

From what I can tell from the start of the message is that it is trying to find an implicit parameter for invariantTuple1 of type Invariant[T1]. Then what? It is trying to see if invariantFoo is a match? It's not a match but it certainly doesn't diverge. The "starting with" part sounds like that is where it starts but invariantFoo doesn't have any implicit parameters so why would that need to look any further?

The next one is also confusing:

invariantFoo is not a valid implicit value for Invariant[T1] because:
diverging implicit expansion for type Invariant[T1]
starting with method invariantTuple1

invariantFoo should be a valid implicit value for Invariant[T1] (assuming T1 is Foo). So how can invariantFoo diverge when it has not implicit parameters?

0 Answers
Related