Closed
Description
Compiler version
3.0.2
Minimized code
import scala.language.implicitConversions
implicit def strToInt(s: String): Int = s.toInt
val x: Int = "1"
Output (at runtime)
java.lang.StackOverflowError
at repl$.rs$line$1$.strToInt(rs$line$1:1)
at repl$.rs$line$1$.strToInt(rs$line$1:1)
at repl$.rs$line$1$.strToInt(rs$line$1:1)
...
Less minimal but more self-contained code
import scala.language.implicitConversions
case class Foo(i: Int) extends AnyVal:
def toFoo = this
case class Bar(i: Int) extends AnyVal
class BarOps(bar: Bar):
def toFoo = Foo(bar.i)
implicit def augmentBar(bar: Bar): BarOps = BarOps(bar)
val x =
implicit def barToFoo(bar: Bar): Foo = bar.toFoo
val foo: Foo = Bar(1)
Output (at runtime)
java.lang.StackOverflowError
at repl$.rs$line$1$.barToFoo$1(rs$line$1:14)
at repl$.rs$line$1$.barToFoo$1(rs$line$1:14)
at repl$.rs$line$1$.barToFoo$1(rs$line$1:14)
...
Expectation
The first snippet was a real puzzler to me and I spent quite a lot of time trying to figure out what was happening there until I found the reason shown in the second snippet (in the first one it's about toInt
being defined on Int
and at the same time added to String
from StringOps
by augmentString
from Predef
).
Not sure whether this would be easy to achieve with the current scheme of resolving implicits but it would be good to avoid the cyclic call of barToFoo
by choosing the method added by the old style extension. Note that there's no cycle if we use a new style extension method instead.
import scala.language.implicitConversions
case class Foo(i: Int) extends AnyVal:
def toFoo = this
case class Bar(i: Int) extends AnyVal
extension (bar: Bar)
def toFoo = Foo(bar.i)
val x =
implicit def barToFoo(bar: Bar): Foo = bar.toFoo
val foo: Foo = Bar(1)