Hello everyone,
The code below compiles with Scala 3.1.0. The execution of the method test()
results in stack overflow error. I would like to know whether this behaviour should be treated as a bug which should be reported.
object X:
opaque type A = Double
object A:
def apply(d: Double): A = d
object Y:
opaque type B = X.A
object B:
def apply(value: X.A): B = value
given Conversion[B, Double] with
def apply(b: B): Double = b // Why not?
def test(): Unit =
val x: Double = Y.B(X.A(0))
Thank you very much!
It produces an SO because the conversion keeps applying to itself until it dies.
I would say this is a bug, since IMHO, an implicit conversion should not be available inside itself; or at least not implicitly, if you need a recursive implicit conversion be explicit about it.
However, I would guess making this exception would be hard since recursive definitions are always allowed.
In any case, implicit conversions are a bug on their own so /shrug.
But this happens only in the case of composed opaque types. The following code does not produce any errors.
object X:
opaque type A = Double
object A:
def apply(d: Double): A = d
given Conversion[A, Double] with
def apply(a: A): Double = a
def test(): Unit =
val x: Double = X.A(0.0)
In this case, the method test()
works as expected.
Sure because in that case, the compiler doesn’t need to apply the conversion itself.
Note that what you are seeing has nothing to do with opaques
, you can reproduce it quite easily like this:
given Conversion[String, Double] with
def apply(str: String): Double = str
val x: Double = "foo"
This is very interesting. When your example is run, the executing thread just hangs. I do not think that this should happen.
If the implicit conversion is omitted, the code does not compile because the type A is opaque.
scala> object X:
| opaque type A = Double
| object A:
| def apply(d: Double): A = d
|
| val x: Double = X.A(0)
-- Error:
6 |val x: Double = X.A(0)
| ^^^^^^
| Found: X.A
| Required: Double
So, it seems that the conversion is used.
In Scala 2, -Xlint warns about an implicit resolving to an enclosing definition.
➜ scala -Xlint
Welcome to Scala 2.13.8 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.
scala> implicit def f(s: String): Int = s
^
warning: Implicit resolves to enclosing method f
warning: 1 feature warning; for details, enable `:setting -feature` or `:replay -feature`
def f(s: String): Int
2 Likes