Type mismatch: can we bind parameters types T and E such that E <: (_,T)


I have the following example of code that attempts to chain
operations (Task[I,O]) and ensure type compatibility. However
in one case where I aggregate values, the intermediate types
between tasks is different.

So I can chain operations Op[I,T] with Op[T,O]. Now what
happens if I want to to chain Op[I,E] with Op[(Exec,E),O].
Can I bind the types T with (Exec,E) where Exec is a trait?

In the code below I use the implicit class operator to attempt
this binding but fail with the error (scala 2.12.6):

[error] AggregateFunc.scala:25:63: type mismatch;
[error]  found   : AggregateFunc.Task[T,O]
[error]  required: AggregateFunc.Task[(AggregateFunc.Exec, E),O]
[error]         case (op:Op[I,E], Func(t)) => AggregateLin[I,E,O](op, t)
[error]                                                               ^
[info] AggregateFunc.Task[T,O] <: AggregateFunc.Task[(AggregateFunc.Exec, E),O]?
[info] false

Code follows next,

object AggregateFunc {

  case class Exec()

  case class Task[I,O]()

  sealed trait Op[I,O]

  final case class NoOp[I,O](s: String) extends Op[I,O]
  final case class Func[I,O](t: Task[I,O]) extends Op[I,O]
  final case class AggregateLin[I,T,O](f: Op[I,T], t: Task[(Exec,T),O]) extends Op[I,O]

    implicit class OpOps[I,T,O](o: Op[T,O]) {
      def |:[E](that: Op[I,E]): Op[I,O] = (that, o) match {
        case (op:Op[I,E], Func(t)) => AggregateLin[I,E,O](op, t)
        case _ => NoOp("")

  def main(args: Array[String]): Unit = {
    val tsk1 = Func(Task[String,Double]())
    //val exec1 = Exec()
    val tsk2 = Func(Task[(Exec,Double),Double]())
    tsk1 |: tsk2

Sure, why not declare it like this:

implicit class OpOps[I,T,O](o: Op[(Exec, T),O]) {
  def |:(that: Op[I,T]): Op[I,O] = (that, o) match {

You can’t do it safely with your original signature.

Thanks for the answer.
I guess I will have to have another operator to deal with this specifically.