scala / scala3

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

Can't call `._1` on values inferred by a GADT match to be a tuple #16590

Closed felher closed 1 year ago

felher commented 1 year ago

Compiler version

3.2.1

Minimized code

enum Tag[A]:
  case MyTuple extends Tag[(String, String)]

def printIt[A](t: Tag[A], a: A): Unit =
  t match
    case Tag.MyTuple => println(a._1)

Output

value _1 is not a member of A
where:    A is a type in method printIt with bounds >: (String, String) and <: (String, String)

Expectation

Should compile fine, since the compiler knows that it is <: (String, String) and (String, String) should have _1. FWIW, annotating the type works. I.e.

    case Tag.MyTuple => println((a: (String, String))._1)

compiles fine.

Scastie Link:

https://scastie.scala-lang.org/4sovEbRjTJOlv0g5WNEUTw

SethTisue commented 1 year ago

Looking at this with Dale.

Both the case class representation and the generic representation of 2-tuple print as (String, String) – if you reach in and make them print differently, you find that in this case the lower bound is the Tuple2 case class but the upper bound is the generic version.

But that mismatch doesn't itself mean that something has already gone wrong. It's the upper bound that matters for member selection and calling ._1 on the generic version should of course work, and in normal circumstances it does. But not when GADT selection healing is needed, apparently!

A related recent fix to typedSelect was #16638, making extension method lookup take GADT constraints into account. typedSelect also has special code for selections on generic tuples, so we guess that code needs a comparable change.