scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.84k stars 1.05k forks source link

Match type in `given` signature causes instance to not be resolved #17907

Open mrdziuban opened 1 year ago

mrdziuban commented 1 year ago

Compiler version

3.3.0, 3.3.1, and the latest 3.4.0-RC4

Minimized code

https://scastie.scala-lang.org/mrdziuban/SnlUnWn8SVmJxCIGflkMbA/3

trait TupleSelector[T, A]

object TupleSelector {
  given head[T <: NonEmptyTuple]: TupleSelector[T, Tuple.Head[T]] = new TupleSelector[T, Tuple.Head[T]]
}

summon[TupleSelector[String *: EmptyTuple, String]]

Output

-- [E172] Type Error: ----------------------------------------------------------
7 |summon[TupleSelector[String *: EmptyTuple, String]]
  |                                                   ^
  |No given instance of type TupleSelector[String *: EmptyTuple, String] was found for parameter x of method summon in object Predef
  |
  |The following import might fix the problem:
  |
  |  import TupleSelector.head
  |

Expectation

The summoned instance should be satisfied by TupleSelector.head

mrdziuban commented 1 year ago

I should have noted, summoning an instance of plain Selector (not Selector.Aux) works as expected, as does calling Selector.apply

summon[Selector[("s" ->> String) *: EmptyTuple, "s"]]
// likeShapeless.Selector[("s" ->> String) *: EmptyTuple, "s"]{type Out = String} = likeShapeless.Selector$$anon$1@669860e1
Selector[("s" ->> String) *: EmptyTuple, "s"]
// likeShapeless.Selector.Aux[("s" ->> String) *: EmptyTuple, "s", String] = likeShapeless.Selector$$anon$1@71dfda31
mrdziuban commented 1 year ago

One more thing to note 😁 this is also reproducible outside of a simple summon call, it's also demonstrated by calling a method with a using Selector.Aux parameter:

scala> import likeShapeless._

scala> def test[T <: Tuple](t: T)(using s: Selector.Aux[T, "s", String]): String = s(t)
def test
  [T <: Tuple]
    (t: T)(using s: likeShapeless.Selector.Aux[T, "s", String]): String

scala> test(("s" ->> "foo") *: EmptyTuple)
-- [E172] Type Error: ----------------------------------------------------------
1 |test(("s" ->> "foo") *: EmptyTuple)
  |                                       ^
  |No given instance of type likeShapeless.Selector.Aux[
  |  (("s" : String) ->> ("foo" : String)) *: EmptyTuple.type, ("s" : String),
  |  String] was found for parameter s of method test
1 error found
mrdziuban commented 1 year ago

What does work (but adds boilerplate) is introducing an additional type parameter V for the third param of Selector.Aux and requiring evidence that V <:< String:

scala> import likeShapeless._

scala> def test[T <: Tuple, V](t: T)(using s: Selector.Aux[T, "s", V], ev: V <:< String): String = s(t)
def test
  [T <: Tuple, V]
    (t: T)
      (using s: likeShapeless.Selector.Aux[T, "s", V], ev: V <:< String): String

scala> test(("s" ->> "foo") *: EmptyTuple)
val res0: String = foo
mrdziuban commented 1 year ago

I've minimized this even more -- does this maybe have something to do with one of the type parameters using a match type?

https://scastie.scala-lang.org/mrdziuban/SnlUnWn8SVmJxCIGflkMbA/3

trait TupleSelector[T, A]

object TupleSelector {
  given head[T <: NonEmptyTuple]: TupleSelector[T, Tuple.Head[T]] = new TupleSelector[T, Tuple.Head[T]]
}

summon[TupleSelector[String *: EmptyTuple, String]]
/*
-- [E172] Type Error: ----------------------------------------------------------
7 |summon[TupleSelector[String *: EmptyTuple, String]]
  |                                                   ^
  |No given instance of type TupleSelector[String *: EmptyTuple, String] was found for parameter x of method summon in object Predef
  |
  |The following import might fix the problem:
  |
  |  import TupleSelector.head
  |
*/
mrdziuban commented 8 months ago

I just ran into another instance of this and am pretty confident that it's caused by using a match type in the given instance's type parameters. I've updated the title to reflect this and the description to show the minimized reproduction