bug icon indicating copy to clipboard operation
bug copied to clipboard

Implicit parameter not resolved from path-dependent type of another parameter’s default value

Open julienrf opened this issue 6 years ago • 5 comments

An implicit parameter whose type is a path-dependent type of another parameter that has a default value is not resolved when the default value is used:

  trait F[A]

  implicit def fInt: F[Int] = null

  trait G {
    type A
  }

  object GInt extends G {
    type A = Int
  }

  def foo(g: G = GInt)(implicit f: F[g.A]): Unit = ()

  foo()
//    ^
// could not find implicit value for parameter f: F[g.A]

  foo(GInt) // OK when the parameter is explicitly supplied, though

This works fine with Dotty, FYI.

You can try online at: https://scastie.scala-lang.org/3WDwOs79SVelY5qS0E8QCg

julienrf avatar Jun 16 '19 15:06 julienrf

It seems that the type of the parameter g is not narrowed to GInt.type when its default value is used.

julienrf avatar Jun 16 '19 15:06 julienrf

I think the problem is that in g: G = GInt the : G is treated as an ascription which widens the single type of GInt leaving A abstract.

milessabin avatar Jun 17 '19 10:06 milessabin

If we don’t define a default value it works:

def foo2(g: G)(implicit f: F[g.A]): Unit = ()

foo2(GInt) // OK, type of parameter `g` is narrowed from `G` to `GInt.type`

julienrf avatar Jun 17 '19 11:06 julienrf

Yup, in that case the compiler sees GInt rather than (effectively) GInt : G (which would also fail).

milessabin avatar Jun 17 '19 11:06 milessabin

Yes there is an ascription in the emitted synthetic for the default:

scala> reify { def foo(g: G = GInt)(implicit f: F[g.A]): Unit = () }
res22: $r.intp.global.Expr[Unit] =
Expr[Unit]({
  def foo(g: $read.G = $read.GInt)(implicit f: $read.F[g.A]): Unit = ();
  <synthetic> def foo$default$1: $read.G = $read.GInt;
  ()
})

The interesting part is that this works:

scala> def foo[B <: G](g: B = GInt)(implicit f: F[g.A]): Unit = ()
foo: [B <: G](g: B)(implicit f: F[g.A])Unit

scala> reify { def foo[B <: G](g: B = GInt)(implicit f: F[g.A]): Unit = () }
res28: $r.intp.global.Expr[Unit] =
Expr[Unit]({
  def foo[B <: $read.G](g: B = $read.GInt)(implicit f: $read.F[g.A]): Unit = ();
  <synthetic> def foo$default$1[B <: $read.G] = $read.GInt;
  ()
})

joroKr21 avatar Jul 18 '19 23:07 joroKr21