Open charpov opened 7 years ago
No one thinks this is a bug? I had no replies on the Scala user list either.
The reason that the first compiles and the second doesn't is that the standard library provides an implicit conversion from Int => BigInt
, but not vice versa.
Welcome to Scala 2.12.2-20170419-092530-unknown (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.
scala> implicitly[Int => BigInt]
res0: Int => BigInt = $$Lambda$1836/347136295@10823d72
scala> implicitly[BigInt => Int]
<console>:12: error: No implicit view available from BigInt => Int.
implicitly[BigInt => Int]
^
Thus the precondition for your implicit def conv[Int, BigInt]
is met, but it's not for conv[BigInt, Int]
.
No. I expect x
to be converted to C[BigInt]
, using the implicit conversion from Int
to BigInt
.
How do you explain that, if I replace def +(that: Base[A]): Base[A]
in Base
with def +(that: Base[A]): Base[A] = ???
, then everything works?
See also discussion at: https://users.scala-lang.org/t/implicits-resolution/981
I experienced similar brokeness with the following simple example:
import scala.util.Try
implicit class MyOption[+A](opt: Option[A]){
def orElse[B >: A](alternative: => Try[B]): Option[B] = opt.orElse(alternative.toOption)
}
Option(1) orElse Try(2)
Intellij IDEA linter says everything is all right, however the compiler gives
Error:(5, 88) type mismatch;
found : scala.util.Try[Int]
required: Option[?]
def get$$instance$$res0 = /* ###worksheet### generated $$end$$ */ Option(4) orElse Try(2)
^
(same happens when analogously overwriting flatMap
)
According to language specs http://scala-lang.org/files/archive/spec/2.12/07-implicits.html#views point 3) this should work, but doesn't apparently. So this is a bug, isn't it?
Is this the same issue?, or should I open a new one?
Agreed. It looks like the same behavior, inconsistent with the specs.
I had another compiler bug, somewhat related, recently resolved by @som-snytt . He seems to know his stuff. I wish he could have a look at this one too.
@schlichtanders I think you encountered this other related issue: https://github.com/scala/bug/issues/9523
Is it fixed in Dotty?
➜ snips cat t10376.scala
object Base {
import scala.language.implicitConversions
implicit def conv[A, B](x: Base[A])(implicit f: A => B): Base[B] = C[B](s"cv $x")
}
abstract class Base[A] {
def +(n: A): Base[A] = this
def +(that: Base[A]): Base[A]
}
case class C[A](tag: String) extends Base[A] {
override def +(that: Base[A]): Base[A] = that
}
object Main extends App {
import Base._
val x = new C[Int]("x")
val y = new C[BigInt]("y")
println((x + y, y + x))
}
➜ snips scalac -version
Scala compiler version 3.0.0-M3 -- Copyright 2002-2020, LAMP/EPFL
➜ snips scalac -d /tmp t10376.scala && scala -classpath /tmp Main
(C(y),C(cv C(x)))
➜ snips
but
➜ snips scalac -d /tmp t10376b.scala && scala -classpath /tmp Main
-- [E007] Type Mismatch Error: t10376b.scala:7:24 ------------------------------
7 | Option(1) orElse Try(2)
| ^^^^^^
| Found: scala.util.Try[Int]
| Required: Option[Any]
1 error found
The idea is to lift an implicit conversion from
A
toB
into one fromC[A]
toC[B]
. LetA
beInt
andB
beBigInt
:The expression
X + x
compiles fine: argumentx
is lifted into aC[BigInt]
. However,x + X
does not compile (x
is not lifted as a target). It seems to me that it should work.Moreover, the expression
x + X
can be compiled if:+
method is removed from classC
(no overloading), or+
method is given an implementation in theBase
class instead of being abstract, then overridden in classC
.I don't think the specs say anything about overloading or abstract/concrete having such an impact on how implicits are resolved, making this behavior buggy (or at least very mysterious).
This is observed in 2.12.2.