It is often useful to use the reify reflection library to see what happens during desugaring (this is the only time I suggest importing something from scala.reflect.runtime , and even then only into REPL during development)
scala> import scala.reflect.runtime.universe.reify import scala.reflect.runtime.universe.reify scala> reify(for { x: Int <- Option(1) } yield x) res5: reflect.runtime.universe.Expr[Option[Int]] = Expr[scala.Option[Int]](Option.apply(1).withFilter(((check$ifrefutable$1) => check$ifrefutable$1: @unchecked match { case (x @ (_: Int)) => true case _ => false })).map(((x: Int) => x)))
The problem is matching case patterns for understanding. Although the compiler verifies that the match is safe (for example, for { x: String <- Option(1) } yield x will not compile), it is still freed from the filtering operation. I do not know why, perhaps, the reason for this, and there is even a small chance that this is a good reason.
You will get a message about filter , because the last compiler in this case. First, he will try to call desugar to call withFilter , and if he does not find withFilter , he will use filter (which, at least in collection library implementations, is generally less efficient in such cases). In the case of WriterT he does not find a single one (since filtering the writer does not make sense in the general case), so he complains about the last one he tried.
The solution is to not use type matching. Write a plain old for { z <- ... } yield z and everything will work fine. In fact, I would advise you never to use font type matching - this is the easiest way to fix reflection problems, ultimately in your code. In this case, the operation will be checked at compile time (at least in obvious cases), but it is still unnecessary and potentially less efficient.
source share