Skip to content

Summoning a mirror for a Tuple produces a class-cast-exception during runtime #12052

Closed
@deusaquilus

Description

@deusaquilus

Compiler version

Latest nightly (i.e. dottyLatestNightlyBuild.get)

Minimized code

Create a simple mirror type object which summons a product mirror, add an extension method for it to be able to be applied to any type:

object MirrorType {
  class Container[T]

  inline def decode[T]: String =
    summonFrom {
      case ev: Mirror.ProductOf[T] =>
        s"Product-${new Container[ev.MirroredElemLabels]}" // This is the part that splices in the cast
      case m: Mirror.SumOf[T] =>
        "Sum"
    }

  inline def generic[T]: MirrorType[T] = 
    new MirrorType[T] {
      def mirrorType: String = decode[T]
    }

  extension[T](inline value: T)
    inline def mirrorType = summonFrom {
      case mt: MirrorType[T] => mt.mirrorType
      case _ => "mirror not found"
    }
}

Then import the context and run it:

object ContextUse {
  def main(args: Array[String]): Unit = {
    val ctx = new MyContext();
    import ctx._
    val tup = ("foo", 1)
    println( tup.mirrorType )
  }
}

Output

A class cast exception will occur

[error] (run-main-2) java.lang.ClassCastException: io.getquill.mytest.ContextUse$$anon$2 cannot be cast to scala.deriving.Mirror$Product
[error] java.lang.ClassCastException: io.getquill.mytest.ContextUse$$anon$2 cannot be cast to scala.deriving.Mirror$Product
[error]         at io.getquill.mytest.ContextUse$$anon$1.mirrorType(Use.scala:10)
[error]         at io.getquill.mytest.ContextUse$.main(Use.scala:10)
[error]         at io.getquill.mytest.ContextUse.main(Use.scala)
[error]         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]         at java.lang.reflect.Method.invoke(Method.java:498)

This is probably because I can see that the following code is being spliced:

{
  val ev: Product {
    type MirroredType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredMonoType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredElemTypes >: Nothing <: Tuple
  } & Product {
    type MirroredMonoType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredLabel >: "Tuple2" <: "Tuple2"
  } {
    type MirroredElemTypes >: *:[String, *:[Int, EmptyTuple]] <: *:[String, *:[Int, EmptyTuple]]
    type MirroredElemLabels >: *:["_1", *:["_2", EmptyTuple]] <: *:["_1", *:["_2", EmptyTuple]]
  } = {
    final class $anon() {
      type MirroredMonoType = Tuple2[String, Int]
    }

    (new $anon(): Object)
  }.$asInstanceOf$[Product {      // WHAT??? You can't cast this to a Product
    type MirroredType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredMonoType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredElemTypes >: Nothing <: Tuple
  } & Product {
    type MirroredMonoType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredType >: Tuple2[String, Int] <: Tuple2[String, Int]
    type MirroredLabel >: "Tuple2" <: "Tuple2"
  } {
    type MirroredElemTypes >: *:[String, *:[Int, EmptyTuple]] <: *:[String, *:[Int, EmptyTuple]]
    type MirroredElemLabels >: *:["_1", *:["_2", EmptyTuple]] <: *:["_1", *:["_2", EmptyTuple]]
  }]
  _root_.scala.StringContext.apply("Product-", "").s(new Container[MirroredElemLabels]())
}

Expectation

Code should compile and run correctly.

Repository

Code is available here:
https://github.com/deusaquilus/class_cast_issue

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions