Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overload resolution with generic implicit only works when there are no parameters #11885

Open
bursauxa opened this issue Feb 12, 2020 · 2 comments
Open

Comments

@bursauxa
Copy link

@bursauxa bursauxa commented Feb 12, 2020

Description

Given the choice between two functions with the following properties:

  • both functions have the same name and list of explicit parameters;
  • one function has a generic type argument, and an implicit parameter based on that generic type argument;
  • the other function has no generic argument and no implicit parameters.

Then the compiler successfully resolves the overload if the list of explicit parameters common to both functions is undefined, whereas it fails to resolve the overload if the list of explicit parameters is defined (even if it is empty).

Reproduction code

Available on scastie for those who want to run it.

case class Wrap[A](value: A)
implicit val wrap: Wrap[Int] = Wrap(5)

// resolution between no parameter and one parameter (which is implicit) succeeds

def foo1: Seq[Int] = 1 :: 2 :: Nil
def foo1[B](implicit wrap: Wrap[B]): Seq[B] = wrap.value :: Nil

println(foo1) // (1, 2)
println(foo1[Int]) // (5)

// resolution between one parameter and two parameters (one of which is implicit) fails
// note: would also fail is the list of parameters is ()

def foo2(bar: Int): Seq[Int] = Seq.fill(bar)(1) ++ Seq.fill(bar)(2)
def foo2[C](bar: Int)(implicit wrap: Wrap[C]): Seq[C] = Seq.fill(bar)(wrap.value)

println(foo2(3)) // would expect (1, 1, 1, 2, 2, 2) but fails to resolve overload
println(foo2[Int](3)) // (5, 5, 5)

Other notes

Tested on Scala 2.13.1 and 2.12.10.

I am not sure which of the two behaviours is correct (should it successfully resolve or not?), but it is disconcerting that it changes based on the presence of explicit parameters.

@som-snytt

This comment has been minimized.

Copy link

@som-snytt som-snytt commented Feb 12, 2020

This seems normal (or normalized) to me, because you take applicable alternatives and pick between them based on the first parameter list.

However, fixed in dotty .22.

➜  snips git:(master) ✗ vi noov.scala
➜  snips git:(master) ✗ ~/dotty/dotty-0.21.0-RC1/bin/dotc noov.scala
-- [E051] Reference Error: noov.scala:20:8 -------------------------------------
20 |println(foo2(3)) // would expect (1, 1, 1, 2, 2, 2) but fails to resolve overload
   |        ^^^^
   |Ambiguous overload. The overloaded alternatives of method foo2 in object Noov with types
   | [C](bar: Int)(implicit wrap: Noov.Wrap[C]): Seq[C]
   | (bar: Int): Seq[Int]
   |both match arguments ((3 : Int))

longer explanation available when compiling with `-explain`
1 error found
➜  snips git:(master) ✗ ~/dotty/dotty-0.22.0-RC1/bin/dotc noov.scala
➜  snips git:(master) ✗ dotr Noov
List(1, 2)
List(5)
List(1, 1, 1, 2, 2, 2)
List(5, 5, 5)
➜  snips git:(master) ✗ 
@lrytz lrytz added this to the Backlog milestone Feb 13, 2020
@lrytz lrytz added the overloading label Feb 13, 2020
@bursauxa

This comment has been minimized.

Copy link
Author

@bursauxa bursauxa commented Feb 13, 2020

Thanks for the answer! The behaviour is consistent with your explanation, although even with the explanation it still does not "feel right" (to me at, least). Glad it's fixed in the latest Dotty RC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.