Skip to content

Overloading and implicit argument result in inconsistent outcomes #22421

Open
@amsen20

Description

@amsen20

Compiler version

3.6.3

Minimized code

Consider two following code examples:
First example:

def printMsg(using hidden: String): Unit =
  println(s"A and ${hidden}")

def printMsg: Unit =
  println("A")

@main def main(): Unit =
  printMsg
  printMsg(using "B")
  val execute = () => {
    given hidden: String = "B"
    printMsg
  }

  execute()

Second example:

def printMsg(msg: String)(using hidden: String): Unit =
  println(s"{msg} and ${hidden}")

def printMsg(msg: String): Unit =
  println(msg)

@main def main(): Unit =
  printMsg("A")

Output

First example's output:

A
A and B
A

Second example's output:

[error] 11 |  printMsg("Hi")
[error]    |  ^^^^^^^^
[error]    |Ambiguous overload. The overloaded alternatives of method printMsg with types
[error]    | (msg: String)(body: (Context) ?=> Unit): Unit
[error]    | (msg: String)(body: (Context) ?=> Unit)(using context: Context): Unit
[error]    |both match arguments (("Hi" : String))
[error]    |
[error]    | longer explanation available when compiling with `-explain`
[error] one error found
[error] (Compile / compileIncremental) Compilation failed

Expectation

There is two problems with outputs:

  1. In the first example, the logical output looks like:
A
A and B
A and B

because the implicit argument is available in the third usage of printMsg, the compiler should infer it and add it there.
2. When a normal argument is added, the printMsg usage becomes ambiguous, which I don't think it should be (I am not an implicit expert). But even if we consider (=>A, ?=>B) the same argument list as (=>A), then why the first example is not ambiguous and compiled successfully?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions