Your implicits are printed by Concrete , and it is invariant here.
Try either
case class Concrete[-T]() extends A[T]
or
implicit val x: A[Parent] = Concrete[Parent]
More words:
Implicits (values ββor representations) must be of an explicit type so that you are never surprised at the type being inferred. Implicit selection is all about type.
He chooses one of your implications using the same rules as the overload resolution conversion, which is used to select alternatives for the overloaded character.
For simple values ββ(not function calls) that boil down to matching or subtyping.
There is also a rule that a definition in a "derived type" (usually a subclass) is preferred.
Here is a test you can do using only commonly available household materials:
scala> :power ** Power User mode enabled - BEEP WHIR GYVE ** ** :phase has been set to 'typer'. ** ** scala.tools.nsc._ has been imported ** ** global._, definitions._ also imported ** ** Try :help, :vals, power.<tab> ** scala> trait A[-T] defined trait A scala> case class Concrete[T](i: Int) extends A[T] defined class Concrete scala> class Parent ; class Kid extends Parent defined class Parent defined class Kid // it will pick X if X isAsSpecific as Y but not conversely scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]]) res0: Boolean = false scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]]) res1: Boolean = false scala> case class Concrete[-T](i: Int) extends A[T] defined class Concrete scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]]) res2: Boolean = false scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]]) res3: Boolean = true
Edit:
Another look at why this is important, what type you are testing:
scala> trait A[-T] defined trait A scala> case class Concrete[T](i: Int) extends A[T] // invariant defined class Concrete scala> class Parent ; class Kid extends Parent defined class Parent defined class Kid scala> implicitly[Concrete[Parent] <:< Concrete[Kid]] <console>:13: error: Cannot prove that Concrete[Parent] <:< Concrete[Kid]. implicitly[Concrete[Parent] <:< Concrete[Kid]] ^ scala> implicit val x: Concrete[Parent] = Concrete[Parent](3) // the inferred type x: Concrete[Parent] = Concrete(3) scala> implicit val y = Concrete[Kid](4) y: Concrete[Kid] = Concrete(4) // both values conform to A[Kid] (because A is contravariant) // but when it puts x and y side-by-side to see which is more specific, // it no longer cares that you were looking for an A. All it knows is // that the values are Concrete. The same thing happens when you overload // a method; if there are two candidates, it doesn't care what the expected // type is at the call site or how many args you passed. scala> implicitly[A[Kid]] <console>:15: error: ambiguous implicit values: both value x of type => Concrete[Parent] and value y of type => Concrete[Kid] match expected type A[Kid] implicitly[A[Kid]] ^
Give them explicit types, and Concrete variance does not matter. You always provide explicit types for your implications, right? Just as the retron tells us?
scala> implicit val x: A[Parent] = Concrete[Parent](3) x: A[Parent] = Concrete(3) scala> implicit val y: A[Kid] = Concrete[Kid](4) y: A[Kid] = Concrete(4) scala> implicitly[A[Kid]] res2: A[Kid] = Concrete(3)