1
votes

I am writing a generic FSM library:

import scala.annotation.tailrec

trait State {
  def isAcceptState: Boolean
}

trait FSM[T <: FSM[T, A, S], -A, +S <: State] { this: T =>
  def state: S

  def resume(input: A): T
}

object FSM {
  @tailrec
  def resumeUntilAccept[T <: FSM[T, A, S], A, S <: State](fsm: T, inputs: Iterator[A]): T = {
    if (inputs.hasNext) {
      val input = inputs.next
      val newFSM = fsm.resume(input)
      if (newFSM.state.isAcceptState) {
        newFSM
      } else {
        resumeUntilAccept[T, A, S](newFSM, inputs) // THIS LINE OF CODE
      }
    } else {
      throw new Exception("not enough inputs")
    }
  }
}

If I remove the type argument list on the line marked // THIS LINE OF CODE, I get the following error:

Main.scala:22: error: inferred type arguments [T,A,Nothing] do not conform to method resumeUntilAccept's type parameter bounds [T <: FSM[T,A,S],A,S <: State]

   resumeUntilAccept(newFSM, inputs)
   ^

Why is Nothing inferred instead of S? And even then, why does it not conform? Nothing is clearly a subtype of State.

2

2 Answers

3
votes

It is limitation of Scala type inference for type constructors, see SI-2712.

You can help compiler by changing type of argument to fsm: FSM[T, A, S]. The following simplified snippet slightly differs from original, but at least it compiles.

trait State

trait FSM[T <: FSM[T, A, S], -A, +S <: State]

object FSM {
  def resumeUntilAccept[T <: FSM[T, A, S], A, S <: State](fsm: FSM[T, A, S], inputs: Iterator[A]): T = {
    val newFSM: T = ???
    resumeUntilAccept(newFSM, inputs)
  }
}
1
votes

I think because type S is not inferred from arguments until FSM is known. So compiler can't compare these S's. "Nothing" not conform to "unknown S" because of same reason.

trait Z[X]
scala> def aaa[A <: Z[B] ,B](a: A):A = aaa(a)
inferred type arguments [A,Nothing] do not conform

scala> def aaa[A <: Z[B], B](a: A):A = aaa[A, B](a) 
aaa: [A <: Z[B], B](a: A)A

or even

scala> def aaa[A <: Z[B], B](a: Z[B]):A = aaa(a) 
aaa: [A <: Z[B], B](a: Z[B])A