milessabin / shapeless

Generic programming for Scala

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Implicit inference for ops.record.Selector doesn't work when Id is passed to a HKT

tksfz opened this issue · comments

Welcome to Scala 2.12.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_172).
Type in expressions for evaluation. Or try :help.

scala> :settings
-Xprint = List()
-Ybrowse = List()
-Ypartial-unification = true
-Yrepl-sync = true
-Ytyper-debug = false
-d = .
-nowarn = false

scala> case class Hkt[F[_]](foo: F[String])
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
defined class Hkt

scala> import shapeless._
import shapeless._

scala> def func[T] = new { def apply[R <: HList](k: Witness)(implicit gen: LabelledGeneric.Aux[T, R], selector: ops.record.Selector[R, k.T]) = 0 }
func: [T]=> AnyRef{def apply[R <: shapeless.HList](k: shapeless.Witness)(implicit gen: shapeless.LabelledGeneric.Aux[T,R],implicit selector: shapeless.ops.record.Selector[R,k.T]): Int}

scala> func[Hkt[Option]].apply('foo)
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
res1: Int = 0

scala> func[Hkt[Id]].apply('foo)
<console>:18: error: could not find implicit value for parameter gen: shapeless.LabelledGeneric[Hkt[[+T]T]]{type Repr = R}
       func[Hkt[Id]].apply('foo)
                          ^

Note that func[Hkt[Id]].apply('foo) can be made to work if I do a (somewhat verbose) work-around where I push implicit gen: LabelledGeneric up to the partially applied class.

For all I know, this could be a bug in the scala compiler.

With -Xlog-implicits (on Scala 2.13.0-RC1):

[info] /home/georgi/work/oss/scratch/src/main/scala/HktId.scala:7:22: shapeless.this.Generic.materialize is not a valid implicit value for shapeless.Generic.Aux[HktId.Hkt[[+T]T],V] because:
[info] hasMatchingSymbol reported error: type mismatch;
[info]  found   : HktId.Hkt[Any]
[info]  required: HktId.Hkt[[+T]T]
[info] Note: Any >: [+T]T, but class Hkt is invariant in type F.
[info] You may wish to define F as -F instead. (SLS 4.5)
[info]   func[Hkt[Id]].apply('foo)
[info]                      ^
[info] /home/georgi/work/oss/scratch/src/main/scala/HktId.scala:7:22: shapeless.this.LabelledGeneric.materializeCoproduct is not a valid implicit value for shapeless.LabelledGeneric[HktId.Hkt[[+T]T]]{type Repr = R} because:
[info] hasMatchingSymbol reported error: could not find implicit value for parameter gen: shapeless.Generic.Aux[HktId.Hkt[[+T]T],V]
[info]   func[Hkt[Id]].apply('foo)
[info]                      ^
[info] /home/georgi/work/oss/scratch/src/main/scala/HktId.scala:7:22: shapeless.this.Generic.materialize is not a valid implicit value for shapeless.Generic.Aux[HktId.Hkt[[+T]T],V] because:
[info] hasMatchingSymbol reported error: type mismatch;
[info]  found   : HktId.Hkt[Any]
[info]  required: HktId.Hkt[[+T]T]
[info] Note: Any >: [+T]T, but class Hkt is invariant in type F.
[info] You may wish to define F as -F instead. (SLS 4.5)
[info]   func[Hkt[Id]].apply('foo)
[info]                      ^
[info] /home/georgi/work/oss/scratch/src/main/scala/HktId.scala:7:22: shapeless.this.LabelledGeneric.materializeProduct is not a valid implicit value for shapeless.LabelledGeneric[HktId.Hkt[[+T]T]]{type Repr = R} because:
[info] hasMatchingSymbol reported error: could not find implicit value for parameter gen: shapeless.Generic.Aux[HktId.Hkt[[+T]T],V]
[info]   func[Hkt[Id]].apply('foo)
[info]                      ^
[error] /home/georgi/work/oss/scratch/src/main/scala/HktId.scala:7:22: could not find implicit value for parameter gen: shapeless.LabelledGeneric[HktId.Hkt[[+T]T]]{type Repr = R}
[error]   func[Hkt[Id]].apply('foo)
[error]                      ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed

That Hkt[Any] is suspicious.

Ah, ofc, it's because this doesn't work either:

val x: Hkt[Id] = Hkt("foo")

[error]  found   : HktId.Hkt[Any]
[error]  required: HktId.Hkt[shapeless.Id]
[error] Note: Any >: shapeless.Id, but class Hkt is invariant in type F.
[error] You may wish to define F as -F instead. (SLS 4.5)
[error]   val x: Hkt[Id] = Hkt("foo")

Code like this is generated by the Generic macro.

Does the contravariant workaround -F actually work? It didn't seem to in my quick attempt.

I wouldn't expect it to work. In this case the error message is not helpful. This is one of the issues with Id - unification failed for Hkt("foo") because it expects a type with shape F[String] but we gave it a naked String. It doesn't know that we actually meant Hkt[Id]("foo"). It looks a bit silly in this case but it can't be fixed in general I think and it's more of a scalac than shapeless issue.

Hmm, actually it works in dotty:

scala> case class Hkt[F[_]](foo: F[String])
// defined case class Hkt

scala> type Id[+T] = T
// defined alias type Id = [+T] => T

scala> val x: Hkt[Id] = Hkt("foo")
val x: Hkt[Id] = Hkt(foo)

So it can be fixed!