4

I'm having a compiler type mismatch error that I do not understand.

Given the following definition of an Elem and a factory (Companion):

object Elem {
  trait Companion[E[~] <: Elem[~]] {
    def apply[S](peer: E[S]#Peer): E[S] // wrap a peer in its elem
  }
}
trait Elem[S] {
  type Peer
}

And given for example an Obj with attributes and a peer type Expr:

trait Expr[S, A]

trait Obj[S] {
  // query an attribute by key
  def attr[E[~] <: Elem[~]](key: String)
                           (implicit c: Elem.Companion[E]): Option[E[S]#Peer]
}

I should be able to do the following:

// process elements with peer `Expr[~, A]`
trait Impl[S, A, E[~] <: Elem[~] { type Peer = Expr[~, A] }] {
  implicit def companion: Elem.Companion[E]

  def test(obj: Obj[S]): Unit =
    obj.attr[E]("foo").fold(()) { ex =>
      val newElem = companion[S](ex)
    }
}

This last bit fails with the brilliant error message:

<console>:62: error: type mismatch; found : E[S]#Peer (which expands to) Expr[S,A] required: E[S]#Peer (which expands to) Expr[S,A] val newElem = companion[S](ex) ^

0__
  • 64,257
  • 16
  • 158
  • 253

1 Answers1

4

I reduced your example to the following:

trait Elem {
    type Peer
}

trait Impl[E[~] <: Elem {type Peer = ~}] {
    def foo[R](peer: E[R]#Peer)

    foo[Int](??? : E[Int]#Peer)
}

where scalac gives

Error:(12, 18) type mismatch;
 found   : this.scala.Peer
    (which expands to)  Int
 required: this.Peer(in method foo)
    (which expands to)  R
    foo[Int](??? : E[Int]#Peer)
             ^^

I'm not sure, but this looks like a Scala bug, since R isn't even in scope at the site of the error -- it seems to have leaked out. Scala seems to be failing to perform the substitution R = Int inside the refinement, allowing the parameter R to remain.

Owen
  • 36,566
  • 13
  • 87
  • 116
  • 1
    [I've made an issue for this](https://issues.scala-lang.org/browse/SI-9222) so we'll see whether people agree that this is a bug. – Owen Mar 14 '15 at 16:37