Skip to content

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

@rssh

Description

@rssh

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions