Given classes Parent and Child.
scala> class Parent
defined class Parent
scala> class Child extends Parent
defined class Child
Define im
Your implicits are typed Concrete
and that 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 views) should have an explicit type so you're never surprised by the inferred type. Picking the implicit is all about the type.
It picks one of your implicits using the same rules as the overloading resolution conversion that is used to pick alternatives of an overloaded symbol.
For simple values (not function calls), that comes down to conformance or subtyping.
There is also the 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 view of why it matters what type you're 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 the variance of Concrete won't matter. You always supply explicit types for your implicits, right? Just like retronym tells us to?
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)