bug icon indicating copy to clipboard operation
bug copied to clipboard

Implicit conversion never applied but influences type inference

Open mariogalic opened this issue 5 years ago • 7 comments

reproduction steps

https://stackoverflow.com/questions/62415172/mere-presence-of-implicit-conversion-makes-the-program-compile-despite-never-bei/62426914

using Scala 2.13.2,

scala> class Bar
class Bar

scala> def f[F[_], A](v: F[A]) = v
def f[F[_], A](v: F[A]): F[A]

scala> implicit def barToList(b: Bar): List[Int] = List(42)
def barToList(b: Bar): List[Int]

scala> f(new Bar)
val res1: Any = Bar@56881196

problem

I would expect implicit conversion would result in

scala> f[List, Int](new Bar)
val res2: List[Int] = List(42)

where the following is inferred

F[_] = List
A = Int 

instead of actual

F[_] = Any
A = Nothing 

Examining the output of -Xprint:typer shows the following implicit conversion never happend

f(barToList(new Bar()))

mariogalic avatar Jun 17 '20 21:06 mariogalic

Curious whether Dotty is different here.

SethTisue avatar Jun 17 '20 21:06 SethTisue

It works in Dotty 0.24.0-RC1:

➜  ~ dotr
Starting dotty REPL...
scala> class Bar
// defined class Bar

scala> def f[F[_], A](v: F[A]) = v
def f[F[_$1], A](v: F[A]): F[A]

scala> implicit def barToList(b: Bar): List[Int] = List(42)
def barToList(b: Bar): List[Int]

scala> f(new Bar)
val res1: List[Int] = List(42)

mariogalic avatar Jun 17 '20 21:06 mariogalic

Just f("": Any) in scala 2 but not 3.

Inferring Any was almost linted under https://github.com/scala/bug/issues/9248. "It makes for a great test of how far we could push abide."

som-snytt avatar Jun 18 '20 07:06 som-snytt

Mutability 😭 Screenshot 2020-06-18 at 22 08 12

joroKr21 avatar Jun 18 '20 20:06 joroKr21

To explain a bit - just testing implicit conversions accumulated type constraints. It also turns into an error with -Yno-predef

joroKr21 avatar Jul 12 '20 18:07 joroKr21

Dotty progressed. I think there is a ticket to improve more specific than F[A].

scala-cli compile --server=false -S 3 t12044.scala
-- [E007] Type Mismatch Error: /home/amarki/snips/t12044.scala:11:6 ------------
11 |    f(new Bar)
   |      ^^^^^^^
   |Found:    Bar
   |Required: F[A]
   |
   |where:    A is a type variable
   |          F is a type variable with constraint <: [_] =>> Any
   |
   |Note that implicit conversions were not tried because the result of an implicit conversion
   |must be more specific than F[A]
   |
   | longer explanation available when compiling with `-explain`
[[syntax trees at end of                     typer]] // /home/amarki/snips/t12044.scala
package <empty> {
  import language.implicitConversions
  class Bar() extends Object() {}
  final lazy module val Test: Test = new Test()
  final module class Test() extends Object(), App { this: Test.type =>
    def f[F[_ >: Nothing <: Any] >: Nothing <: Any, A >: Nothing <: Any](v: F[A]
      ): F[A] = v
    implicit def barToList(b: Bar): List[Int] = List.apply[Int]([42 : Int]*)
    Console.println(
      {
        Test.f[[_] =>> Any, Any](new Bar())
      }
    )
  }
}

1 error found
Compilation failed

With -Yno-predef, Scala 2 seems to be stuck.

scala-cli compile --server=false -S 2 t12044.scala
/home/amarki/snips/t12044.scala:11: error: type mismatch;
 found   : Bar
 required: List[A]
    f(new Bar)
      ^
[[syntax trees at end of                     typer]] // t12044.scala
package <empty> {
  import scala.language.implicitConversions;
  class Bar extends scala.AnyRef {
    def <init>(): Bar = {
      Bar.super.<init>();
      ()
    }
  };
  object Test extends AnyRef with App {
    def <init>(): Test.type = {
      Test.super.<init>();
      ()
    };
    def f[F[_] >: [_]Nothing <: [_]Any, A](v: F[A]): F[A] = v;
    implicit def barToList(b: Bar): List[Int] = scala.`package`.List.apply[Int](42);
    scala.Console.println(f(new Bar()))
  }
}

1 error
Compilation failed

som-snytt avatar May 06 '25 03:05 som-snytt

Reopening: as pointed out by @joroKr21 this issue is about the limitation in inference.

the problem is that type variable bounds were collected from all implicit conversions instead of only the one that is applicable


I noticed, the "fixed in Scala 3" is true for 3.0, but current Scala 3 doesn't compile the code.

class Bar
class T {
  def f[F[_], A](v: F[A]) = v
  implicit def barToList(b: Bar): List[Int] = List(42)
  def t = f(new Bar)
}

gives

-- [E007] Type Mismatch Error: /Users/luc/code/scala/scala13/sandbox/T.scala:5:12
5 |  def t = f(new Bar)
  |            ^^^^^^^
  |Found:    Bar
  |Required: F[A]
  |
  |where:    A is a type variable
  |          F is a type variable with constraint <: [_] =>> Any
  |
  |Note that implicit conversions were not tried because the result of an implicit conversion
  |must be more specific than F[A]

probably due to https://github.com/scala/scala3/issues/15670#issuecomment-1184279375

lrytz avatar Oct 23 '25 13:10 lrytz