Skip to content

Assertion failed during macro generation (Inlined term in Apply) #8029

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
rssh opened this issue Jan 18, 2020 · 2 comments
Closed

Assertion failed during macro generation (Inlined term in Apply) #8029

rssh opened this issue Jan 18, 2020 · 2 comments

Comments

@rssh
Copy link
Contributor

rssh commented Jan 18, 2020

minimized code

(note, that ready to run project is attached. Also it's situated in dotty-break-while-00 branch on github https://github.com/rssh/dotty-cps-async/tree/dotty-break-while-00

let we have next macro definitions:

package c
  
import scala.quoted._
import scala.quoted.matching._

trait CB[T]

object CBF {
   def pure[T](value:T): CB[T] = ???
   def map[A,B](fa:CB[A])(f: A=>B):CB[B] = ???
   def flatMap[A,B](fa:CB[A])(f: A=>CB[B]):CB[B] = ???
}


case class CpsChunk[T](prev: Seq[Expr[_]], last:Expr[CB[T]])

    def toExpr(given QuoteContext): Expr[CB[T]] =
      if (prev.isEmpty)
        last
      else
        Expr.block(prev.toList,last)

trait CpsChunkBuilder[T:Type]

  def isAsync: Boolean

  def create(): CpsChunk[T]

  def append[A:Type](chunk: CpsChunk[A]): CpsChunk[A]

  protected def fromFExpr(f: Expr[CB[T]]): CpsChunk[T] =
          CpsChunk(Seq(),f)

  def flatMap[A:Type](t: Expr[T => CB[A]])(given QuoteContext): CpsChunk[A] =
                 CpsChunk[A](Seq(),
                      '{ CBF.flatMap(${create().toExpr})(${t}) }
                 )

  def flatMapIgnore[A:Type](t: Expr[CB[A]])(given QuoteContext): CpsChunk[A] =
           CpsChunk[A](Seq(),
                 '{ CBF.flatMap(${create().toExpr})(_ => ${t}) }
           )

  def transformed(given QuoteContext): Expr[CB[T]] = create().toExpr


object CpsChunkBuilder

   def sync[T:Type](f:Expr[T])(given QuoteContext):CpsChunkBuilder[T] =
     new CpsChunkBuilder[T] {
        override def isAsync = false
        override def create() = fromFExpr('{ CBF.pure($f) })
        override def append[A:Type](e: CpsChunk[A]) =
            CpsChunk(f +: e.prev, e.last)
     }

   def async[T:Type](f:Expr[CB[T]])(given QuoteContext):CpsChunkBuilder[T] =
     new CpsChunkBuilder[T] {
        override def isAsync = true
        override def create() = fromFExpr(f)
        override def append[A:Type](e: CpsChunk[A]) = flatMapIgnore(e.toExpr)
     }


erased def await[T](f: CB[T]):T = ???


object Async {

  inline def transform[T](expr: =>T): CB[T] =
    ${ Async.transformImpl[T]('expr) }

 def transformImpl[T:Type](f: Expr[T])(given qctx: QuoteContext): Expr[CB[T]] =
    rootTransform[T](f).transformed
  def rootTransform[T:Type](f: Expr[T])(given qctx: QuoteContext): CpsChunkBuilder[T] =
     import qctx.tasty.{_, given}
     import util._
     f match
         case Const(c) =>
                        CpsChunkBuilder.sync(f)
         case '{ _root_.c.await[$fType]($ft) } =>
                        val awBuild = CpsChunkBuilder.async(ft)
                        awBuild.asInstanceOf[CpsChunkBuilder[T]]
         case '{ while ($cond) { $repeat }  } =>
                        val cpsCond = Async.rootTransform(cond)
                        val cpsRepeat = Async.rootTransform(repeat)
                        val isAsync = cpsCond.isAsync || cpsRepeat.isAsync
                        CpsChunkBuilder.async(
                          '{
                             def _whilefun(): CB[T] = {
                               ${cpsCond.flatMap[T]( '{ c =>
                                 if (c) {
                                   ${cpsRepeat.flatMapIgnore(
                                       '{ _whilefun() }
                                  ).toExpr}
                                 } else {
                                  CBF.pure(()).asInstanceOf[CB[T]]
                                 }
                               }).toExpr
                               }
                             }
                             _whilefun()
                          })
        case _ =>
             val fTree = f.unseal.underlyingArgument
             fTree match {
                case Apply(fun,args) =>
                   CpsChunkBuilder.sync(f)
                case Block(prevs,last) =>
                   val rPrevs = prevs.map{
                     case d: Definition =>
                       ???
                     case t: Term =>
                       t.seal match
                          case '{ $p:$tp } =>
                             Async.rootTransform(p)
                          case other =>
                             ???
                   }
                   val rLast = Async.rootTransform[T](last.seal.asInstanceOf[Expr[T]])
                   val lastChunk = rLast.create()
                   val blockResult = rPrevs.foldRight(lastChunk)((e,s) => e.append(s))
                   val isAsync = rLast.isAsync || rPrevs.exists(_.isAsync)
                   CpsChunkBuilder.async[T](blockResult.toExpr)
                case Ident(name) =>
                   CpsChunkBuilder.sync(f)
                case _ =>
                   printf("fTree:"+fTree)
                   ???
             }

}

And try to eval macro in other compilation unit:

package c
  
import org.junit.{Test,Ignore}
import org.junit.Assert._

class TestBS1While

  def cbBool(b:Boolean): CB[Boolean] = ???

 // Dotty crash.
 // TODO: minimize and submit bug.
 //
  @Test def tWhileC1_11(): Unit =
     val c = Async.transform[Unit]{
        while(await(cbBool(false))) {
          await(cbBool(false))
        }
     }
     assert(true)
Stack trace ```scala [error] |Exception occurred while executing macro expansion. [error] |java.lang.AssertionError: assertion failed [error] | at dotty.DottyPredef$.assertFail(DottyPredef.scala:16) [error] | at dotty.tools.dotc.ast.tpd$.Apply(tpd.scala:45) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTerm$1(TreeUnpickler.scala:1091) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTerm(TreeUnpickler.scala:1212) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTerm$1(TreeUnpickler.scala:1104) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTerm(TreeUnpickler.scala:1212) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTerm$1(TreeUnpickler.scala:1115) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTerm(TreeUnpickler.scala:1212) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler.unpickle(TreeUnpickler.scala:107) [error] | at dotty.tools.dotc.core.tasty.DottyUnpickler.computeRootTrees(DottyUnpickler.scala:59) [error] | at dotty.tools.dotc.ast.tpd$TreeProvider.rootTrees(tpd.scala:1107) [error] | at dotty.tools.dotc.core.tasty.DottyUnpickler.rootTrees(DottyUnpickler.scala:41) [error] | at dotty.tools.dotc.ast.tpd$TreeProvider.tree(tpd.scala:1111) [error] | at dotty.tools.dotc.core.tasty.DottyUnpickler.tree(DottyUnpickler.scala:41) [error] | at dotty.tools.dotc.core.quoted.PickledQuotes$.unpickle(PickledQuotes.scala:131) [error] | at dotty.tools.dotc.core.quoted.PickledQuotes$.unpickleExpr(PickledQuotes.scala:66) [error] | at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.unpickleExpr(ReflectionCompilerInterface.scala:38) [error] | at scala.runtime.quoted.Unpickler$.unpickleExpr$direct(Unpickler.scala:16) [error] | at c.Async$.rootTransform$$anonfun$8$6$$anonfun$5$$anonfun$5$3$$anonfun$3(Async.scala:95) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readHole(TreeUnpickler.scala:1293) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTerm$1(TreeUnpickler.scala:1204) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTerm(TreeUnpickler.scala:1212) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTerm$1(TreeUnpickler.scala:1115) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTerm(TreeUnpickler.scala:1212) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTerm$1(TreeUnpickler.scala:1104) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTerm(TreeUnpickler.scala:1212) [error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTerm$1(TreeUnpickler.scala:1123) ... ```

When looking at problem, I see that Apply assume RefTree or GenericApply, but actual value is Inlined.

dotty-cps-minimized-break-while11.tar.gz

@rssh
Copy link
Contributor Author

rssh commented Jan 21, 2020

I wrote a fix, but not 100% sure, that this will be the right way.
https://github.com/rssh/dotty/pull/2/files

rssh added a commit to rssh/dotty that referenced this issue Jan 21, 2020
@rssh
Copy link
Contributor Author

rssh commented Jan 21, 2020

looks, like just allwing Inlined also works.
https://github.com/rssh/dotty/pull/3/files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants