Dotty: Compiler crash with recursive type matches and quotes

Created on 10 Apr 2019  路  4Comments  路  Source: lampepfl/dotty

When generating code that uses matchers to compute types, the code compiles, but running it results in the runtime error:

34 |    def reify[A] given Type[A]   = m => '{ k => ${ Effects[L].reify[E] {   m(   a =>    Effects[L].reflect[E]('k(a))) } }}
   |                                                                                                              ^
   |                                        value apply is not a member of R
   | This location is in code that was inlined at Bug.scala:34

Here is the full example code (sorry for not being able to minimize further):

package examples

import scala.quoted._

object bug extends App {

  val toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
  implied for scala.quoted.Toolbox = toolbox

  sealed trait HList
  sealed trait HNil extends HList
  sealed trait ::[E, T <: HList] extends HList

  type STM[A, L <: HList] = L match {
    case HNil => Expr[A]
    case e :: rs => (Expr[A] => STM[e, rs]) => STM[e, rs]
  }

  type Stm[A, L <: HList] = L match {
    case HNil => A
    case e :: rs => (A => Stm[e, rs]) => Stm[e, rs]
  }

  trait Effects[L <: HList] {
    def reify[A] given Type[A]: STM[A, L] => Expr[Stm[A, L]]
    def reflect[A] given Type[A]: Expr[Stm[A, L]] => STM[A, L]
  }
  implied empty for Effects[HNil] {
    def reify[A] given Type[A] = m => m
    def reflect[A] given Type[A] = m => m
  }
  // for reify, we need type tags for E and also strangely for L.
  implied cons [E, L <: HList] given Effects[L] given Type[E] given Type[L] for Effects[E :: L] {
    def reify[A] given Type[A]   = m => '{ k => ${ Effects[L].reify[E] {   m(   a =>    Effects[L].reflect[E]('k(a))) } }}
    def reflect[A] given Type[A] = m =>    k =>    Effects[L].reflect[E] { m('{ a => ${ Effects[L].reify[E](   k('a)) } })}
  }
  def Effects[L <: HList] given Effects[L]: Effects[L] = the[Effects[L]]

  type RS = Boolean :: RS2
  type RS2 = Int :: String :: HNil

  val m: STM[Int, RS] = k => k('{42})

  // compiles, but results in a runtime error:
  //    println(Effects[RS].reify[Int] { m }.show)
  //
  // the implicit search results in the following value:
  //    val effects = cons[Boolean, RS2] given (cons[Int, String :: HNil] given (cons[String, HNil] given empty))
  //
  // so the above is equivalent to:
  //    println(effects.reify[Int] { m }.show)
  //
  // error:
  //  37 |    def reify[A] given Type[A]   = m => '{ k => ${ Effects[L].reify[E] {   m(   a =>    Effects[L].reflect[E]('k(a))) } }}
  //   |                                                                                                              ^
  //   |                                        value apply is not a member of R
  //   | This location is in code that was inlined at Bug.scala:37

  // manually inlining reify works
  //  val res : Expr[Stm[Int, RS]] = '{ k => ${ Effects[RS2].reify[Boolean] { m(a => Effects[RS2].reflect[Boolean]('k(a))) }}}
  //  println(res.show)
}

On the example: Both STM and Stm are matchers that given a list of types (HList) compute a new type. The resulting type is produced by iterating CPS.

metaprogramming

Most helpful comment

From @biboudis minimization I minimized it further to

import scala.quoted._

object Test {

  val toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
  implied for scala.quoted.Toolbox = toolbox

  sealed trait HList
  sealed trait HNil extends HList
  sealed trait ::[E, T <: HList] extends HList

   type Stm[A, L <: HList] = L match {
    case HNil => A
    case e :: rs => (A => Stm[e, rs]) => Stm[e, rs]
  }

  def main(args: Array[String]): Unit = {

    val boom = '{ (x: Int) => (??? : Stm[Int, Int :: Int :: HNil]) }
    val foo: Expr[Int] =
     '{ println(); ${
       boom('{4})('{ (a4: Int) => (k4: Int => Int) => ${ 'k4('a4) } } )('{ (a7: Int)  => a7 })
       } }
    println(foo.show)
  }
}
19 |    val boom = '{ (x: Int) => (??? : Stm[Int, Int :: Int :: HNil]) }
   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                              value apply is not a member of R
true
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at dotty.tools.vulpix.ChildJVMMain.runMain(ChildJVMMain.java:40)
        at dotty.tools.vulpix.ChildJVMMain.main(ChildJVMMain.java:47)
Caused by: java.lang.Exception: Could not extract Expr(<pickled tasty>)
        at dotty.tools.dotc.quoted.QuoteDriver.withTree$$

All 4 comments

From @biboudis minimization I minimized it further to

import scala.quoted._

object Test {

  val toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
  implied for scala.quoted.Toolbox = toolbox

  sealed trait HList
  sealed trait HNil extends HList
  sealed trait ::[E, T <: HList] extends HList

   type Stm[A, L <: HList] = L match {
    case HNil => A
    case e :: rs => (A => Stm[e, rs]) => Stm[e, rs]
  }

  def main(args: Array[String]): Unit = {

    val boom = '{ (x: Int) => (??? : Stm[Int, Int :: Int :: HNil]) }
    val foo: Expr[Int] =
     '{ println(); ${
       boom('{4})('{ (a4: Int) => (k4: Int => Int) => ${ 'k4('a4) } } )('{ (a7: Int)  => a7 })
       } }
    println(foo.show)
  }
}
19 |    val boom = '{ (x: Int) => (??? : Stm[Int, Int :: Int :: HNil]) }
   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                              value apply is not a member of R
true
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at dotty.tools.vulpix.ChildJVMMain.runMain(ChildJVMMain.java:40)
        at dotty.tools.vulpix.ChildJVMMain.main(ChildJVMMain.java:47)
Caused by: java.lang.Exception: Could not extract Expr(<pickled tasty>)
        at dotty.tools.dotc.quoted.QuoteDriver.withTree$$

Great! Thanks for looking at the issue

Even after merging #6322 this issue still occurs, so I guess it was not the reason for it.

@b-studios it looks like it is fixed now. I added the full code that is in the first snippet in #6840 and all seemed to work.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

noti0na1 picture noti0na1  路  3Comments

liufengyun picture liufengyun  路  3Comments

mcku picture mcku  路  3Comments

julienrf picture julienrf  路  3Comments

ohze picture ohze  路  3Comments