Assuming that A class called 'summoner' was defined, that is capable of summoning implicit views from the scope:
case class Summoner[R]() {
def summon[T](v: T)(implicit ev: T => R): R = ev(v)
}
I found that it works most of the time, but there are cases where it doesn't work, e.g. the following is a (not too) short case which uses the singleton-ops
library:
import shapeless.Witness
import singleton.ops.+
import singleton.ops.impl.Op
trait Operand {
def +[
X >: this.type <: Operand,
Y <: Operand
](that: Y): Op2[X, Y] = {
Op2[X, Y](this, that)
}
}
object Operand {
abstract class ProvenToBe[O <: Arity]()(implicit val out: O) extends Operand {}
object ProvenToBe {
implicit class Trivial[O <: Arity, T <: ProvenToBe[O]](
val self: T
) extends Proof {
override type Out = O
override def out: Out = self.out
}
}
}
trait Proof extends Serializable {
def self: Operand
type Out <: Arity
def out: Out
}
object Proof {
trait Out_=[+O <: Arity] extends Proof {
type Out <: O
}
trait Invar[S] extends Out_=[Arity.Const[S]] {
type SS = S
}
}
trait Arity extends Operand {}
object Arity {
trait Const[S] extends Arity {
type SS = S
}
object Const {
implicit class Same[S](val self: Const[S]) extends Proof.Invar[S] {
override type Out = Const[S]
override def out: Const[S] = self
}
}
class FromOp[S <: Op]() extends Const[S]
object FromOp {
implicit def summon[S <: Op](implicit s: S): FromOp[S] = new FromOp[S]()
}
class FromLiteral[S <: Int](val w: Witness.Lt[Int]) extends Const[S] {}
object FromLiteral {
implicit def summon[S <: Int](implicit w: Witness.Aux[S]): FromLiteral[S] =
new FromLiteral[S](w)
}
def apply(w: Witness.Lt[Int]): FromLiteral[w.T] = {
FromLiteral.summon[w.T](w) //TODO: IDEA inspection error
}
}
case class Op2[
+A1 <: Operand,
+A2 <: Operand
](
a1: A1,
a2: A2
) extends Operand {}
object Op2 {
implicit class ProveInvar[
A1 <: Operand,
A2 <: Operand,
S1,
S2
](
val self: Op2[A1, A2]
)(
implicit
bound1: A1 => Proof.Invar[S1],
bound2: A2 => Proof.Invar[S2]
) extends Proof.Invar[S1 + S2] {
override type Out = Arity.FromOp[S1 + S2]
override def out: Out = new Arity.FromOp[S1 + S2]()
}
}
When attempting to use the implicit view as-is:
implicit val a = Arity(3)
implicit val b = Arity(4)
val op = a + b
op: Proof // implicit view works
But when using the summoner:
val summoner = Summoner[Proof]()
summoner.summon(op) // oops
[Error] /home/peng/git/shapesafe/spike/src/main/scala/edu/umontreal/kotlingrad/spike/arity/package.scala:141: No implicit view available from edu.umontreal.kotlingrad.spike.arity.package.Op2[edu.umontreal.kotlingrad.spike.arity.package.Arity.FromLiteral[Int(3)],edu.umontreal.kotlingrad.spike.arity.package.Arity.FromLiteral[Int(4)]] => edu.umontreal.kotlingrad.spike.arity.package.Proof.
one error found
FAILURE: Build failed with an exception.
This error message looks quite bland, almost resembles a common implicit type mismatch error, but previous usage has already culled out that possibility. So my questions are:
What's the cause of this behaviour?
How do you know it?
op: Proof
is used – Strobile