bug
bug copied to clipboard
Implicit parameter not resolved from path-dependent type of another parameter’s default value
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
It seems that the type of the parameter g is not narrowed to GInt.type when its default value is used.
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.
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`
Yup, in that case the compiler sees GInt rather than (effectively) GInt : G (which would also fail).
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;
()
})