-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Labels
Description
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.