scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.89k stars 1.06k forks source link

Ambiguous overload between varargs and non-varargs #9688

Closed eloots closed 4 years ago

eloots commented 4 years ago

Minimized code

Calling a method on the Java Log4J library with 2 arguments (the last one in a position where a varargs polymorphic version exists) results in the compiler reporting an error.

  context.log.error("Received unexpected message in state 'trackProgress': {}", msg)

Compiling the above line results in the following error message:

Output

[error] -- [E051] Reference Error: /Users/ericloots/Trainingen/LBT/lunatech-scala-2-to-scala3-course/exercises/exercise_000_sudoku_solver_initial_state/src/main/scala/org/lunatechlabs/dotty/sudoku/SudokuProgressTracker.scala:43:20
[error] 43 |        context.log.error("Received unexpected message in state 'trackProgress': {}", msg)
[error]    |        ^^^^^^^^^^^^^^^^^
[error]    |Ambiguous overload. The overloaded alternatives of method error in trait Logger with types
[error]    | (x$0: String, x$1: Object*): Unit
[error]    | (x$0: String, x$1: Object): Unit
[error]    |both match arguments (("Received unexpected message in state \'trackProgress\': {}" : String), (msg : org.lunatechlabs.dotty.sudoku.SudokuProgressTracker.SudokuDetailState))

Expectation

The sample line of code given above should compile (as it does in pre-0.27.0 and of course Scala 2.x)

eloots commented 4 years ago

@smarter Created a ready to run example to reproduce the issue.

smarter commented 4 years ago

Turns out this isn't even specific to Java varargs:

object Test {
  def foo(x: Any*): Unit = {}
  def foo(x: Any): Unit = {}

  foo("") // error: ambiguous overloads
}
smarter commented 4 years ago

@odersky Any idea what difference there might be between Scala 2 and Dotty's overloading resolution that leads to the previous example being ambiguous?

smarter commented 4 years ago

It's also worth noting that the following is not ambiguous in Scala 2 nor Dotty:

object Test {
  def foo(x: String*): Unit = {}
  def foo(x: String): Unit = {}

  foo("")
}

I don't know why using String instead of Any makes a difference.

dwijnand commented 4 years ago

Is it because Seq[Any] <: Any?

smarter commented 4 years ago

That should be fine, but maybe what's going on is that Any* <: Any in Dotty but not in Scala 2. In Dotty, Any* is encoded using a synthetic class: <repeated>[Any], I don't know how it's represented in Scala 2 but there's a comment hinting that * is magic somehow (https://github.com/scala/scala/blob/074dae29c9a6bd3a22c4c6289f224ec28110fdfd/src/compiler/scala/tools/nsc/typechecker/Infer.scala#L339) so it might not be a subtype of any regular type.

smarter commented 4 years ago

Hmm it's also a class in Scala 2, but it's "special" whatever that means: https://github.com/scala/scala/blob/074dae29c9a6bd3a22c4c6289f224ec28110fdfd/src/reflect/scala/reflect/internal/Definitions.scala#L417 https://github.com/scala/scala/blob/074dae29c9a6bd3a22c4c6289f224ec28110fdfd/src/reflect/scala/reflect/internal/Definitions.scala#L1462-L1473

som-snytt commented 4 years ago

A couple of links via gitter:

lampepfl/dotty#6230 still open from a pre-pandemic year, with a long conversation that ends with Martin: "The rabbit hole just got deeper."

The canonical scala 2 ticket scala/bug#8342 doesn't actually link to all the issues, we need paulp-level linking.

Sample subtlety scala/bug#4728.

I think scala/bug#8344 was resolved incorrectly [but what do I know].

Gitter converts links to text so they are no longer cut/pasteable. [Edit: github converts them back. Synergy!]

He-Pin commented 4 years ago

It's anoying in Java too

foo(Object ... values) //1
foo(List<Object> values) //2
List<String> values = ...
foo(values) //link to 1
List values2 = values;
foo(values2) //link to 2
smarter commented 4 years ago

Fixed in https://github.com/lampepfl/dotty/pull/9732