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 fails when one parameter requires an implicit conversion #10576

Open
julienrf opened this issue Oct 30, 2017 · 3 comments
Open

Comments

@julienrf
Copy link

I’ve discovered this issue when working on the collections strawman.

import scala.reflect.ClassTag

// Base type introducing a flatMap method
trait Coll[A] {
  def flatMap[B](f: A => Coll[B]): Coll[B]
}

// An `Arr[A]` is not a `Coll[A]` ...
trait Arr[A]

// ... but there is an `ArrOps` decorator
trait ArrOps[A] extends Coll[A] {
  // we overload `flatMap` for the specific needs of `Arr`
  def flatMap[B : ClassTag](f: A => Coll[B]): Arr[B]
}

object Prelude {
  import scala.language.implicitConversions
  implicit def arrToArrOps[A](array: Arr[A]): ArrOps[A] = ???
}

object Usage extends App {
  
  import Prelude._
  
  val array: Arr[Arr[Int]] = ???
  
  // This line doesn’t compile
  array.flatMap(x => x)
  //  overloaded method value flatMap with alternatives:
  //    [B](f: Arr[Int] => Coll[B])(implicit evidence$1: scala.reflect.ClassTag[B])Arr[B] 
  //    [B](f: Arr[Int] => Coll[B])Coll[B]
  //   cannot be applied to (Arr[Int] => Arr[Int])
  
  // However if we explicitly trigger the implicit conversion to `Coll`, it compiles:
  array.flatMap(x => (x: Coll[Int]))
  
  // Also, if we remove the overload the first one compiles too (even though it requires
  // two implicit conversions: one to make the `flatMap` method available and one to make
  // the the result of the function passed to `flatMap` a `Coll`
  
}

Live snippet: https://scastie.scala-lang.org/uRjdJ280TOqv3az8iGGSOQ

Tested with Scala 2.12.4 and 2.13.0-M2.

@julienrf
Copy link
Author

Actually, something similar already works currently with Array and Traversable. I’m wondering if there is a trick to apply to get it work in my case too…

@adriaanm
Copy link
Contributor

Possibly a dupe of #10526, which @milessabin is working on fixing: scala/scala#6139

@milessabin
Copy link

I don't think this is related to #10526 and scala/scala#6139 doesn't fix it.

The following fails for the same reason as @julienrf's example,

class A
class B
class C
object C {
  implicit def cToA(c: C): A = ???
}

object Test {
  def foo(a: () => A): Unit = ()
  def foo(b: () => B): Unit = ()

  foo(() => new A) // OK
  foo(() => new B) // OK
  foo(() => new C) // Fails
  foo(() => (new C: A)) // OK

}
error: overloaded method value foo with alternatives:
  (b: () => B)Unit <and>
  (a: () => A)Unit
 cannot be applied to (() => C)
  foo(() => new C) // Fails
  ^
one error found

The problem in the third case is in inferMethodAlternative: there are no directly applicable alternatives and it fails without considering the possible implicit conversion.

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

No branches or pull requests

3 participants