TypeVars can't specialize Scope declarations
Below are a few examples involving type aliases and refinement types that show how among several equivalent types, some can be resolved implicitly while others cannot.
object Main {
type With[A, B] = A with B
class TC[A]
object TC {
def apply[A](implicit tc: TC[A]): TC[A] = tc
implicit def tc[A, B]: TC[A With B] = new TC
}
trait Trait { def head: Int }
TC[Trait With Serializable] // ok
TC[Trait with Serializable] // ok
type Struct = { def head: Int }
TC[Struct With Serializable] // ok
TC[Struct with Serializable] // missing (1)
type TwSeq = Trait With Seq[Int]
TC[TwSeq With Serializable] // ok
TC[TwSeq with Serializable] // ok
type SwSeq = Struct With Seq[Int]
TC[SwSeq With Serializable] // ok
TC[SwSeq with Serializable] // missing (2)
TC[(Trait With Seq[Int]) with Serializable] // missing (3)
TC[(Trait with Seq[Int]) with Serializable] // ok
TC[(Struct With Seq[Int]) with Serializable] // missing (4)
TC[(Struct with Seq[Int]) with Serializable] // missing (5)
}
I looked more closely into (1). -Xlog-implicits reports:
Information:(16, 5) Main.this.TC.tc is not a valid implicit value for Main.TC[Main.Struct with Serializable] because:
hasMatchingSymbol reported error: polymorphic expression cannot be instantiated to expected type;
found : [A, B]Main.TC[Main.With[A,B]]
(which expands to) [A, B]Main.TC[A with B]
required: Main.TC[Main.Struct with Serializable]
(which expands to) Main.TC[AnyRef{def head: Int} with Serializable]
TC[Struct with Serializable] // missing (1)
Further debugging reveals that at some point implicit resolution checks if the types below are compatible:
Main.TC[Main.With[?A,?B]] weak_<:< Main.TC[Main.Struct with Serializable] // false
Strangely enough though:
Main.TC[Main.With[?A,?B]] =:= Main.TC[Main.Struct with Serializable] // true
Intuitively I would expect A =:= B to imply A <:< B. But I'm not sure what role type variables play here.
Scala version: 2.12.3 Java version: Oracle 1.8.0_144
Somewhat related to https://github.com/scala/bug/issues/9770.
@milessabin I don't know about that. But here is how to reproduce inconsistencies in the subtype relation involving type variables:
import scala.reflect.runtime
val universe = runtime.universe.asInstanceOf[runtime.JavaUniverse]
import universe._
val tvar = TypeVar(symbolOf[Set[Any]].typeParams.head)
val struct = typeOf[{ def i: Int }]
val pat = refinedType(tvar :: typeOf[Serializable] :: Nil, NoSymbol)
val tpe = refinedType(struct :: typeOf[Serializable] :: Nil, NoSymbol)
println(tvar =:= struct) // true
println(tvar.constr) // _= AnyRef{def i: Int}
println(tpe =:= pat) // true
println(tpe <:< pat) // true
println(pat <:< tpe) // false
println(pat <:< struct) // false
println(tvar <:< struct) // true
println(tvar.member(TermName("i"))) // <none>
println(tvar.inst.member(TermName("i"))) // method i
Further minimization:
object Test {
type Parent
type Scope = { val x: Int }
implicit def refined[A]: Parent with A = ???
implicitly[Parent with Int] // ok
implicitly[Parent with Scope] // missing
}
A leaky abstraction:
?A <:< Scope and Parent with ?A <:< Parent with Int,
but not Parent with ?A <:< Parent with Scope