Skip to content

Type inference failure while picking among conversions #13102

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

Open
vhminh opened this issue May 7, 2025 · 2 comments
Open

Type inference failure while picking among conversions #13102

vhminh opened this issue May 7, 2025 · 2 comments
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) infer

Comments

@vhminh
Copy link

vhminh commented May 7, 2025

Reproduction steps

Scala version: 2.13.16

//> using scala 2.13.16
import scala.language.implicitConversions

trait LowPriorityConversions {
  implicit def convertIterable1[A, I[T] <: Iterable[T]](iterable: I[A]): String = {
    "convertIterable1 wins"
  }

  // implicit def convertIterable2[A, I[_]](iterable: I[A])(implicit ev: I[A] <:< Iterable[A]): String = {
  //   "convertIterable2 wins"
  // }
}

object Conversions extends LowPriorityConversions {
  implicit def convertMap[K, V, M[A, B] <: Map[A, B]](map: M[K, V]): String = {
    "convertMap wins"
  }
}

object OverloadTest {
  // force conversion to String
  def printStr(str: String): Unit = {
    println(str)
  }

  def main(args: Array[String]): Unit = {
    import Conversions._
    printStr(Map("key" -> "value"))               // ok: got "convertMap wins"
    printStr(Map("key" -> "value").map(identity)) // expect "convertMap wins", but got "convertIterable1 wins"
  }
}

Problem

  • Map#map has 2 alternatives: map[K2, V2](f: ((K, V)) => (K2, V2)): Map[K2, V2] and map[B](f: ((K, V)) => B): Iterable[B]. The first one is more specific so I expect Map("key" -> "value").map(identity) to return a Map, not an Iterable
  • It works as expected when we replace convertIterable1 with convertIterable2
  • This doesn't happen on Scala 3.3.5
@som-snytt
Copy link

I don't understand the details yet but -Vlog:typer suggests that it (spuriously) can't infer type args for convertMap but can for convertIterable1.

[log typer] infer method inst Conversions.convertMap[K, V, M], tparams = List(type K, type V, type M), args = List(immutable.this.Map[?K2,scala.this.Nothing]), pt = String, lobounds = List(scala.this.Nothing, scala.this.Nothing, scala.this.Nothing), parambounds = List(, , [A, B] <: Map[A,B])
[log typer] error tree = <argument>
[log typer] implicit adapt failed: no type parameters for method convertMap: (map: M[K,V]): String exist so that it can be applied to arguments (immutable.this.Map[?K2,scala.this.Nothing])
 --- because ---
no unique instantiation of type variable K2 could be found
test/files/run/t13102.scala:22: convertMap is not a valid implicit value for scala.this.Function1[immutable.this.Map[?K2,scala.this.Nothing],String] because:
no type parameters for method convertMap: (map: M[K,V]): String exist so that it can be applied to arguments (immutable.this.Map[?K2,scala.this.Nothing])
 --- because ---
no unique instantiation of type variable K2 could be found
    import Conversions._
           ^

I also don't understand why convertIterable2 fails with

[log typer] implicit adapt failed: Cannot prove that scala.collection.immutable.Iterable[A] <:< Iterable[A].

Then convertMap eventually succeeds (after failing to infer type args) because it tries picking the overload first, and that allows it to proceed successfully.

I'll tweak the title to reflect that it's a problem with type inference and not overload resolution per se.

@som-snytt som-snytt changed the title Less specific method alternative is chosen when implicit conversion is applied Type inference failure while picking overloaded conversions May 10, 2025
@som-snytt som-snytt added infer fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) labels May 10, 2025
@som-snytt
Copy link

for reference, the Map construction is not involved (but produces noisy debug)

//> using scala 2.13.16
//> using options -Xsource:3-cross -Vlog:typer -Vdebug -Vtyper
import scala.language.implicitConversions

trait LowPriorityConversions {
  implicit def convertIterable1[A, I[T] <: Iterable[T]](iterable: I[A]): String = "convertIterable1 wins"

  //implicit def convertIterable2[A, I[_]](iterable: I[A])(implicit ev: I[A] <:< Iterable[A]): String = "convertIterable2 wins"
}

object Conversions extends LowPriorityConversions {
  implicit def convertMap[K, V, M[A, B] <: Map[A, B]](map: M[K, V]): String = "convertMap wins"
}

object OverloadTest {
  // force conversion to String
  def printStr(str: String): Unit = println(str)

  def sut = Map("key" -> "value")

  def main(args: Array[String]): Unit = {
    import Conversions._
    //printStr(Map("key" -> "value"))               // ok: got "convertMap wins"
    //printStr(Map("key" -> "value").map(identity)) // expect "convertMap wins", but got "convertIterable1 wins"
    printStr(sut.map(identity)) // expect "convertMap wins", but got "convertIterable1 wins"
  }
}

@som-snytt som-snytt changed the title Type inference failure while picking overloaded conversions Type inference failure while picking among conversions May 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) infer
Projects
None yet
Development

No branches or pull requests

2 participants