Here is the same scenario with Try.
def test3: Try [String] = Try { throw new RuntimeException(); "success" }
test3 // works fine.
implicit def toTry[T](a: => T): Try[T] = { println("convert to try!"); Try(a) }
def test4: Try[String] = { throw new RuntimeException(); "success"}
{ throw new RuntimeException(); "success" }.getOrElse("failed") // works fine.
// type checker finds that the return type of block is String,
// which does not have a getOrElse
// so it falls back on implicit conversion for the block. as follows:
toTry( {throw new RuntimeException(); "success" }).getOrElse("failed")
test4 // gives runtime exception
// test4 has an *expected type* of Try[String]
// The return type of block is String ("success")
// So implicit conversion kicks in from ':=> String' to 'Try[String]'
// this conversion is not for the outer block but for the inner block.
// so in essence, it is converted to:
def test4: Try[String] = { throw new RuntimeException(); toTry({"success"}) }
refer https://issues.scala-lang.org/browse/SI-3237 for more details on this.