Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
deusaquilus opened this issue Apr 11, 2021 · 6 comments · Fixed by #12062
Closed

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

deusaquilus opened this issue Apr 11, 2021 · 6 comments · Fixed by #12062
Assignees
Milestone

Comments

@deusaquilus
Copy link
Contributor

deusaquilus commented Apr 11, 2021

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

@odersky
Copy link
Contributor

odersky commented Apr 11, 2021

Looks like a duplicate of #11961 and #11542.

@deusaquilus
Copy link
Contributor Author

Makes sense. Whatever the case, I checked this against the latest Dotty build and it is happening.

@deusaquilus
Copy link
Contributor Author

Also, making my methods transparent doesn't fix the problem.

@deusaquilus
Copy link
Contributor Author

deusaquilus commented Apr 11, 2021

@odersky @bishabosha I see that the original issue #11542 was created Feb 26th. What are the chances that this will be fixed by the 3.0.0 release? This issue is making it impossible for me to return Tuples from any Quill queries. (Sorry if I sound demanding, I'm just really worried)

E.g. the following is impossible due to this issue:

inline def q =
  quote {
    for {
      p <- query[Person]
      a <- query[Address] if (p.id == a.fk)
    } yield {
      (p.name, a.street) // Summons a mirror for this tuple which blows up with ClassCast Exception
    }
  }

deusaquilus added a commit to zio/zio-protoquill that referenced this issue Apr 12, 2021
odersky added a commit to dotty-staging/dotty that referenced this issue Apr 12, 2021
Mirror support runs in PostTyper to add new members to mirrors generated
during Typer. But some anonymous mirrors are generated during inlining.
We need to add the missing methods for them as well.

Fixes scala#11542
Fixes scala#11961
Fixes scala#12052
odersky added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2021
Mirror support runs in PostTyper to add new members to mirrors generated
during Typer. But some anonymous mirrors are generated during inlining.
We need to add the missing methods for them as well.

Fixes scala#11542
Fixes scala#11961
Fixes scala#12052
@deusaquilus
Copy link
Contributor Author

This is great. Thank you!

@odersky
Copy link
Contributor

odersky commented Apr 13, 2021

You are welcome! Glad that we could fix it for 3.0.

michelou pushed a commit to michelou/scala3 that referenced this issue Apr 14, 2021
Mirror support runs in PostTyper to add new members to mirrors generated
during Typer. But some anonymous mirrors are generated during inlining.
We need to add the missing methods for them as well.

Fixes scala#11542
Fixes scala#11961
Fixes scala#12052
@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants