Closed justcoon closed 1 year ago
Thanks for the report.
I could reproduce the issue without Scala.js nor Java classes. All that's really needed is an invariant SAM type that is not a platform SAM type:
abstract class Parent
trait Function[A, B] extends Parent {
def apply(a: A): B
}
object Test {
def test(x: (Int, Int), f: Function[? >: (Int, Int), ? <: Boolean]): Boolean =
f.apply(x)
def isLess(left: Int, right: Int): Boolean = {
// working
val f = new Function[(Int, Int), Boolean] {
override def apply(t: (Int, Int)): Boolean = left.compareTo(right) <= 0
}
test((left, right), f)
// NOT working
test(
(left, right),
_ => left.compareTo(right) <= 0
)
}
def main(args: Array[String]): Unit = {
println(isLess(1, 2))
println(isLess(1, 2))
println(isLess(2, 1))
}
}
> scalac tests/run/hello.scala
> scala Test
Exception in thread "main" java.lang.AbstractMethodError
at Test$.test(hello.scala:9)
at Test$.isLess(hello.scala:21)
at Test$.main(hello.scala:26)
at Test.main(hello.scala)
So this is not Scala.js-specific.
I think ExpandSAMs
is doing something bad because it generates:
Test.test(Tuple2.apply[Int, Int](left, right),
{
def $anonfun(_$1: (Int, Int)): Boolean =
int2Integer(left).compareTo(int2Integer(right)).<=(0)
{
final class $anon() extends Parent(),
Function[? >: (Int, Int), ? <: Boolean] {
final def apply(_$1: (Int, Int)): Boolean = $anonfun(_$1)
}
new Parent with Function[? >: (Int, Int), ? <: Boolean] {...}()
}
}
)
Notice the ?
type parameters in the extends
clause. That's illegal. It should generate extends Function[(Int, Int), Boolean]
instead.
In fact, I wonder whether typer
is not to blame instead. It already generates:
Test.test(Tuple2.apply[Int, Int](left, right),
{
def $anonfun(_$1: (Int, Int)): Boolean =
int2Integer(left).compareTo(int2Integer(right)).<=(0)
closure($anonfun:Function[? >: (Int, Int), ? <: Boolean])
}
)
Not downright illegal, but since it obviously can correctly construct (Int, Int)
and Boolean
in def $anonfun
(as opposed to ? >: (Int, Int)
and ? <: Boolean
), perhaps it is already equipped to use the correct types in the closure(...)
node.
Also, if Function
itself is an abstract class
, instead of a trait
, then the typer refuses the code:
-- Error: tests/run/hello.scala:21:37 ------------------------------------------
21 | _ => left.compareTo(right) <= 0
| ^
|result type of lambda is an underspecified SAM type Function[? >: (Int, Int), ? <: Boolean]
so apparently it is already trying to protect itself from this issue, but it only does that for class
es and not for trait
s. That's clearly broken.
Aaaand ... I knew I had seen this somewhere before. It's a duplicate of #16065.
Compiler version
scala 3.2.0, scalajs 1.11.0
Minimized code
https://scastie.scala-lang.org/kwQJBQRlSneSBEP93zzz8w
Output
Expectation
code will run without issues