Skip to content

Compiletime Operations and Tuples with Recursion for Typeclass derivation. #17169

Open
@fabianhjr

Description

@fabianhjr

I'm probably doing this in a very weird way (learning metaprogramming and wanted to try some stuff as I was reading the guides and watching some videos)

Asked about the following on SO and was directed to open an issue here by Dimytro Mitin ( https://stackoverflow.com/q/75873631/539209 )

Compiler version

3.2.2

Minimized code

import scala.compiletime.*

trait Show[T]:
  def show(t: T): String

object Show:
  given Show[Int] with
    def show(t: Int): String = t.toString

  given Show[String] with
    def show(t: String): String = t

transparent inline def showForTuple[T <: Tuple]: Show[T] =
  inline erasedValue[T] match
    case _: EmptyTuple => (new Show[EmptyTuple] {
      override def show(n: EmptyTuple): String = ""
    }).asInstanceOf[Show[T]]

    case _: (t *: EmptyTuple) => (new Show[t *: EmptyTuple] {
      val showHead = summonInline[Show[t]]

      override def show(tup: t *: EmptyTuple): String = showHead.show(tup.head)
    }).asInstanceOf[Show[T]]

    case _: (t *: ts) => (new Show[t *: ts] {
      val showHead = summonInline[Show[t]]
      val showTail = showForTuple[ts]

      override def show(tup: t *: ts): String =
        showHead.show(tup.head) + ", " + showTail.show(tup.tail)
    }).asInstanceOf[Show[T]]

@main def Test: Unit =
  showForTuple[Int *: String *: EmptyTuple].show((1, "hola mundo")) // Works
  showForTuple[(Int, String)].show((1, "hola mundo")) // Crashes

Output

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    Test$$anon$1.show(Lscala/Product;)Ljava/lang/String; @7: invokevirtual
  Reason:
    Type 'scala/Product' (current frame, stack[1]) is not assignable to 'scala/Tuple2'
  Current Frame:
    bci: @7
    flags: { }
    locals: { 'Test$$anon$1', 'scala/Product', 'scala/Product' }
    stack: { 'Show', 'scala/Product' }
  Bytecode:
    0000000: 2ab6 002a 2b4d 2cb6 0030 b800 36b8 003a
    0000010: b900 3d02 002a b600 3f2b 4eb2 0044 2db6
    0000020: 0047 b600 4bb9 003d 0200 ba00 5700 00b0
    0000030:                                        

	at Test$.main(test.scala:36)
	at Test.main(test.scala)

Expectation

Undefined

Workaround

Thanks Il Totore in Scala Discord

import scala.compiletime.*
import cats.Show

given Show[EmptyTuple] = _ => ""
lazy val given_Show_EmptyTuple: cats.Show[EmptyTuple]

given [A, T <: Tuple](using showA: Show[A], showT: Show[T]): Show[A *: T] =
  _ match
    case h *: EmptyTuple => showA.show(h)
    case h *: t => showA.show(h) + ", " + showT.show(t)

transparent inline def showForTuple[T <: Tuple]: Show[T] =
  inline erasedValue[T] match
    case _: EmptyTuple => summonInline[Show[EmptyTuple]].asInstanceOf[Show[T]]
    case _: (t *: EmptyTuple) => summonInline[Show[t *: EmptyTuple]].asInstanceOf[Show[T]]
    case _: (t *: ts) => summonInline[Show[t *: ts]].asInstanceOf[Show[T]]

@main def Test =
  showForTuple[Int *: String *: EmptyTuple].show((1, "hola mundo")) // works
  showForTuple[(Int, String)].show((1, "hola mundo")) // Also works?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions