【发布时间】:2018-03-03 19:29:01
【问题描述】:
(注意:这个问题自 Scala 2.13 起已修复,请参见此处:https://github.com/scala/scala/pull/6050)
我正在研究一个涉及链式隐式的 Scala 类型系统。这个系统在很多情况下都像我预期的那样运行,但在其他情况下却因分散扩展而失败。到目前为止,我还没有对分歧提出一个很好的解释,我希望社区可以为我解释一下!
这是一个重现问题的简化类型系统:
object repro {
import scala.reflect.runtime.universe._
trait +[L, R]
case class Atomic[V](val name: String)
object Atomic {
def apply[V](implicit vtt: TypeTag[V]): Atomic[V] = Atomic[V](vtt.tpe.typeSymbol.name.toString)
}
case class Assign[V, X](val name: String)
object Assign {
def apply[V, X](implicit vtt: TypeTag[V]): Assign[V, X] = Assign[V, X](vtt.tpe.typeSymbol.name.toString)
}
trait AsString[X] {
def str: String
}
object AsString {
implicit def atomic[V](implicit a: Atomic[V]): AsString[V] =
new AsString[V] { val str = a.name }
implicit def assign[V, X](implicit a: Assign[V, X], asx: AsString[X]): AsString[V] =
new AsString[V] { val str = asx.str }
implicit def plus[L, R](implicit asl: AsString[L], asr: AsString[R]): AsString[+[L, R]] =
new AsString[+[L, R]] { val str = s"(${asl.str}) + (${asr.str})" }
}
trait X
implicit val declareX = Atomic[X]
trait Y
implicit val declareY = Atomic[Y]
trait Z
implicit val declareZ = Atomic[Z]
trait Q
implicit val declareQ = Assign[Q, (X + Y) + Z]
trait R
implicit val declareR = Assign[R, Q + Z]
}
以下是行为的演示,有一些工作案例,然后是不同的失败:
scala> :load /home/eje/divergence-repro.scala
Loading /home/eje/divergence-repro.scala...
defined module repro
scala> import repro._
import repro._
scala> implicitly[AsString[X]].str
res0: String = X
scala> implicitly[AsString[X + Y]].str
res1: String = (X) + (Y)
scala> implicitly[AsString[Q]].str
res2: String = ((X) + (Y)) + (Z)
scala> implicitly[AsString[R]].str
<console>:12: error: diverging implicit expansion for type repro.AsString[repro.R]
starting with method assign in object AsString
implicitly[AsString[R]].str
【问题讨论】: