Skip to content

Overloading Resolution + Names / Defaults + Varargs + Auto-Tupling + Spec #8342

Open
@scabug

Description

@scabug

This ticket collects multiple issues around overloading resolution. See also comments in scala/scala#3562, scala/scala#3583.


Auto-tupling is not mentioned at all in the spec. One could argue that the following violates the spec: both alternatives are applicable, but the compiler picks the one that requires using a default argument, even though these are supposed to be eliminated if there are multiple alternatives.

object t {
  def f(a: (Int, Int)) = 0
  def f(a: Int, b: Int, c: Int = 0) = 1
}
t.f(1,2) // returns 1, been like that since 2.8

Maybe a better way to spec it would be to ignore auto-tupling for overloading resolution and say that auto-tupling is tried last, when nothing else works. This is probably what the implementation does: the first alternative is not applicable (if you don't have auto-tupling), the second is.


Overloading resolution in the spec starts by selecting alternatives that are "applicable to expressions (e1 ... en) of types (shape(e1) ... shape(en)". It seems to me this is an implementation detail that is not needed for the spec, because afterwards we test if the alternatives are applicable to expressions (e1 ... en) of types (S1 .. Sn).

Also, the current implementation seems to ignore the vararg-marker (:_*) when testing shape matches. This is probably safe (more alternatives are kept at this stage), but not according to the (IMO unnecessary) part of the spec.


The spec of overloading resolution is incomplete when it comes to interpreting an argument x = e, which can be an assignment or a named argument.

The current implementation has a bug when selecting the most specific alternative if a setter does not return Unit:

object t {
  def x: Int = 33
  def x_=(a: Int): String = "hui"
  def f(a: String) = "f-string"
  def f(u: Unit) = "f-unit"
  def g() = f(x = 100)   // BUG: should pick f-string, but picks f-unit
}
t.g()

A different problem is that the current implementation, applicable alternatives are filtered based on parameter names. For each argument expression x = e, only those alternatives defining a parameter x are kept. This fixes #4592, but it disallows interpreting the argument as assignment. For example:

object t { def f(x: Unit) = 0; def f(z: Int) = 1 }
var z = 0
t.f(z = 10) // ambiguous reference to overloaded in scala 2.9, returns 1 in scala 2.10/2.11

One idea to fix this: in doTypedApply, type-check the argument expression x = e in a silent context and to find out if the expression would be a valid assignment. If so, store its type (does not have to be Unit, due to setters) in the NamedType. Overloading resolution would then know if the expression is a valid assignment.

Alternative solution: Decide if x = e is an assignment or a named argument purely based on the syntax. It seems that is what dotty does. Thread on scala internals

foo(x = e)    // always a named argument
foo { x = e } // always an assignment expression
foo((x = e))  // assignment expression
foo({x = e})  // assignment expression

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions