bug
bug copied to clipboard
No implicit view available from A => B despite having one in scope
Reproduction steps
Scala version: 2.13.8
sealed trait ImplicitlyStable[A, +B]
object ImplicitlyStable {
implicit def convertibleToStable[A, B](implicit
aToB: A => B,
bToB: ImplicitlyStable[B, B]
): ImplicitlyStable[A, B] = ???
}
object Test {
def testConvertibleToStable[A, B](implicit
aToB: A => B,
bToB: ImplicitlyStable[B, B]
): ImplicitlyStable[A, B] =
implicitly[ImplicitlyStable[A, B]]
}
Problem
This fails with:
[error] !I e: ImplicitlyStable[A, B]
[error] ImplicitlyStable.convertibleToStable invalid because
[error] !I aToB: A => B
[error] No implicit view available from A => B.
[error]
[error] implicitly[ImplicitlyStable[A, B]]
[error] ^
This seems like it ought to compile. The implicit view is right there in the parameters.
A few surprising changes make it compile:
- Removing
AfromImplicitlyStable - Changing
BinImplicitlyStableto be invariant - Removing either
aToBorbToBfromconvertibleToStable - Changing
implicitly[ImplicitlyStable[A, B]]toImplicitlyStable.convertibleToStable[A, B]
If I change implicitly[ImplicitlyStable[A, B]] to ImplicitlyStable.convertibleToStable then it fails with:
[error] both method $conforms in object Predef of type [A]A => A
[error] and value aToB of type A => B
[error] match expected type A => B
[error] ImplicitlyStable.convertibleToStable
[error] ^
Is it one of those situations where is inferring Nothing. If so why?
If I add:
private def unexpected: Nothing = sys.error("Unexpected invocation")
implicit def nothingStableAmbig1[A]: ImplicitlyStable[Nothing, A] = unexpected
implicit def nothingStableAmbig2[A]: ImplicitlyStable[Nothing, A] = unexpected
implicit def nothingStableAmbig3[A]: ImplicitlyStable[A, Nothing] = unexpected
implicit def nothingStableAmbig4[A]: ImplicitlyStable[A, Nothing] = unexpected
then sure enough I get:
[error] /Users/jason/src/bug-reports/src/main/scala/com/goodcover/slinky/stable/Main.scala:31:15: ambiguous implicit values:
[error] both method nothingStableAmbig3 in object ImplicitlyStable of type [A]com.goodcover.slinky.stable.ImplicitlyStable[A,Nothing]
[error] and method nothingStableAmbig4 in object ImplicitlyStable of type [A]com.goodcover.slinky.stable.ImplicitlyStable[A,Nothing]
[error] match expected type com.goodcover.slinky.stable.ImplicitlyStable[A,B]
[error] implicitly[ImplicitlyStable[A, B]]
[error] ^
I still can't figure out why it is so quick to infer Nothing
Change the order of the implicit arguments in convertibleToStable - put bToB: ImplicitlyStable[B, B] first and aToB: A => B second.
When the compiler searches an implicit function of the form
implicit def foo[A, B](implicit arg: Something[A, B], ...): ...
then both A and B are chosen for the entire subsequent implicit algorithm by the first arguments which specify them.
In your case the compiler sees it needs an implicit aToB: A => B for any free A and B. Well it's easy enough to infer B to Nothing and it gets A => Nothing for free so it does that.
If you put bToB first then B is fixed to what you actually need - the thing from scope - and then in the second argument the compiler picks A => B correctly from the implicits in scope, with a correctly-chosen B.
Whether this behaviour is a bug or not - I don't know. The way it behaves makes sense to me with my (very rudimentary) understanding of the compiler. This is not a technical explanation and I'm sure somebody who knows more can come and correct my specifics!
Note: Chaning +B to B means Nothing is no longer a candidate to satisfy the second type argument of the implicit def, so it would not find A => Nothing as an option for the first argument. Hence it works with an invariant B as written in the opening post