scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

SAM convert not work in overloaded method parameter. #12560

Closed counter2015 closed 1 year ago

counter2015 commented 2 years ago

Reproduction steps

Scala Version: 2.13.8

I cant reproduce it by raw scala, it's only reproduce in akka function.

I'm not sure if the bug is also related to akka.

Add akka library in sbt

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.5.32"

And then compile following code

import akka.actor.ActorSystem

import scala.concurrent.duration._

object BugExample {

  def main(args: Array[String]): Unit = {
    val system = ActorSystem("test")
    implicit val ec = system.dispatcher

    system.scheduler.schedule(1.second, 10.seconds, () => println("why cant convert this to Runnable"))
  }
}

And here is the schedule method

  def schedule(initialDelay: FiniteDuration, interval: FiniteDuration, runnable: Runnable)(
      implicit executor: ExecutionContext): Cancellable

Compile failed with error

BugExample.scala:11:56: type mismatch;
[error]  found   : () => Unit
[error]  required: Runnable
[error]         system.scheduler.schedule(1.second, 10.seconds, () => println("why cant convert this to Runnable"))

Problem

Following code works well

import akka.actor.ActorSystem

import scala.concurrent.ExecutionContext
import scala.concurrent.duration._

object BugExample {

  // self defined function works well
  def test1() = {
    def schedule(initialDelay: FiniteDuration, interval: FiniteDuration, runnable: Runnable)(
      implicit executor: ExecutionContext): Unit = {
      println(s"$initialDelay $interval")
      runnable.run()
    }

    val system = ActorSystem("test")
    implicit val ec = system.dispatcher

    schedule(1.second, 10.seconds, () => println("works well 1"))
  }

  // declare type explicitly works well
  def test2() = {

    val system = ActorSystem("test")
    implicit val ec = system.dispatcher

    val f: Runnable = () => println("works well 2")

    system.scheduler.schedule(1.second, 10.seconds, f)
  }

  def main(args: Array[String]): Unit = {
    test1()
    test2()
  }

}

IMO, the compiler should convert () => scala.Unit to Runnable . What's the problem here ?


Environment:

sbt: 1.6.2 jdk: corretto 17, openjdk 11

Jasper-M commented 2 years ago

schedule is an overloaded method, with one overload being a subtype of another overload.

object X {
  def schedule(x: Duration, f: Runnable) =  1
  def schedule(x: FiniteDuration, f: Runnable) =  2
}

X.schedule(3.seconds, () => println("doesn't work"))
som-snytt commented 2 years ago

The previous comment "subtype of an overload" ought to say "is more specific than another alternative".

scala> import concurrent._, duration._
import concurrent._
import duration._

scala> object X {
     |   def schedule(x: Duration, f: Runnable) =  1
     |   def schedule(x: FiniteDuration, f: Runnable) =  2
     | }
object X

scala>

scala> X.schedule(3.seconds, () => println("doesn't work"))
                                ^
       error: type mismatch;
        found   : () => Unit
        required: Runnable

scala> def g(f: Runnable) = 42
def g(f: Runnable): Int

scala> g(() => println("it's a runnable"))
val res1: Int = 42

I don't know why that is a problem, but unrelatedly I hope github offers a feature to ensure that snippets compile, as in scaladoc. That would amaze me.

Jasper-M commented 2 years ago

The previous comment "subtype of an overload" ought to say "is more specific than another alternative".

I refuse.

jxnu-liguobin commented 2 years ago

I investigated for a while. It seems that this is caused by overloading, but the specific reason is not clear and I'm still a novice. Seems to be here? https://github.com/scala/scala/blob/933b3c616b56ad1ab15be365121b7bc3ffa98b66/src/reflect/scala/reflect/internal/Types.scala#L1212

SethTisue commented 2 years ago

has anyone gone digging for past tickets on the interactions between SAM conversion and overloading? I feel like that's a feature intersection that has come up before, perhaps repeatedly