Scala unexpected type inference troubleshooting

175 Views Asked by At

I'm struggling a long time with incorrect type inference of the O output type. Why does scalac see Int instead of (Int,String) ? :

trait Request[I,+O,C[_]]
case class Get[I, O, C[_]](storeName: String, arg: C[I]) extends Request[I,(I,O),C]
object Question {
  val get: Request[Int,(Int,String), List] = Get("play", List(1))
}

[error]  found   : com.viagraphs.idb.Get[Int,Int,List]
[error]  required: com.viagraphs.idb.Request[Int,(Int, String),List]
[error]       val get: Request[Int,(Int,String), List] = Get("play", List(1))

Please ignore W,R,ValidKey type classes, they are irrelevant here I guess.

Exactly the same happens this way :

case class Append[I : W, O : R : ValidKey](storeName: String, arg: List[I]) extends Request[I,(O,I),List]
object Question {
  val get: Request[Int,(Int,String), List] = Get("play", List(1))
}
val append: Request[String,(Int,String), List] = Append("play", List("foo"))

[error]  found   : com.viagraphs.idb.Append[String,String]
[error]  required: com.viagraphs.idb.Request[String,(Int, String),List]
[error]       val append: Request[String,(Int,String), List] = Append("play", List("foo"))

I tried to deal with this using -Ytyper-debug but it is really hard core stuff, I didn't understand its mechanics.

UPDATE: I reproduced it using Ordering type class, any idea what implicit resolution rule is not satisfied?

  trait Req[I,O]
  case class Insert[I : Ordering, O : Ordering](arg: I) extends Req[I,O]
  def execute[I,O](req: Req[I,O]): O = null.asInstanceOf[O]

  def main() = {
    val result: Int = execute(Insert("test"))  
  }

error: type mismatch;
 found   : String
 required: Int
    val result: Int = execute(Insert("test"))  
2

There are 2 best solutions below

3
On BEST ANSWER

Ok, I tried to put together a simple example and it compiles just fine on my machine, using sbt 0.13.7 on scala 2.11.4

package example

object Main extends App {
  trait Request[I,+O,C[_]]

  trait W[A]
  trait R[A]
  trait ValidKey[A]

  implicit val wString = new W[String]{}
  implicit val rInt = new R[Int]{}
  implicit val validKeyInt = new ValidKey[Int]{}

  case class Append[I: W, O: R : ValidKey](storeName: String, arg: List[I]) extends Request[I,(O,I),List]
  val append: Request[String,(Int,String), List] = Append("play", List("foo"))

}

Am I missing anything?

1
On

Try to change it to this:

Get[Int, String, List]("play", List(1))

I was able to reproduce your issue in Intellij, though it had a different type inference issue, but this seems to make the error go away.