Scala: expression's type is not compatible with formal parameter type

Viewed 1427
trait Ingredient{}

case class Papperoni() extends Ingredient{}
case class Mushroom() extends Ingredient{}

trait ToppingDef[T] {
}

object PepperoniDef extends Serializable with ToppingDef[Papperoni] {
}

object MushroomDef extends Serializable with ToppingDef[Mushroom] {
}

class Oven[T <: Ingredient](val topping:ToppingDef[T]) {
}

class Pizza {
  def cook = {
    val topping =
      if(someCondition()) { PepperoniDef }
      else { MushroomDef}

    new Oven(topping) // <-- build error here
  }
}

I am using Scala 2.11. This example is somewhat contrived but I’ve stripped out everything unrelated to the problem to provide a concise example.

The error I get on the last line is:

Error:(26, 5) no type parameters for constructor Oven: (topping: ToppingDef[T])Oven[T] exist so that it can be applied to arguments (Serializable with ToppingDef[_ >: Papperoni with Mushroom <: Product with Serializable with Ingredient])
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Serializable with ToppingDef[_ >: Papperoni with Mushroom <: Product with Serializable with Ingredient]
 required: ToppingDef[?T]
    new Oven(topping)

However changing the last line to this for example:

new Oven(PepperoniDef)

builds fine. So the compiler has no problem finding the type when the parameter is passed explicitly like this.

Also, removing the Serializable trait from PepperoniDef and MushroomDef like this:

object PepperoniDef extends ToppingDef[Papperoni] {
}

object MushroomDef extends ToppingDef[Mushroom] {
}

also builds. However in my case I need the Serializable.

I think I can probably restructure the code to work around this if necessary but I would like to understand what's going on, I don't know why the type is ambiguous in the first case, or why the presence of the Serializable trait has any effect. Thanks in advance for any insights.

EDIT: Thank you for the replies, very helpful. I think the most concise fix is to change this:

val topping =

to this:

val topping:ToppingDef[_ <: Ingredient] =

Which cures the build error and does not require a change to the generic classes, which I would like to keep as simple an unannotated as possible so as to have Scala infer as much type information as possible.

This doesn't answer the question of why the presence of Serializable has any effect on this.

2 Answers
Related