Open
Description
Compiler version
3.3.1-RC1-bin-20230216-2507577-NIGHTLY
Minimized code
Consider the following macro definition (the macro annotation extracts the number v
that is applied to locally
in inlineMethod
):
import scala.annotation.MacroAnnotation
import scala.quoted.*
class annotation extends MacroAnnotation:
def transform(using Quotes)(tree: quotes.reflect.Definition) =
import quotes.reflect.*
tree match
case tree: ClassDef =>
val List(DefDef(name, paramss, tpt, Some(body))) = tree.body: @unchecked
val rhs = body match
case Inlined(_, _, Block(List(Apply(_ /* `locally` */, List(rhs))), _)) => rhs
val method = DefDef.copy(tree.body.head)(name, paramss, tpt, Some(rhs.changeOwner(tree.body.head.symbol)))
List(ClassDef.copy(tree)(tree.name, tree.constructor, tree.parents, tree.self, List(method)))
Macro call site:
transparent inline def inlineMethod(v: Int) =
locally(v)
0
@annotation
class Test:
def method = inlineMethod(42)
Output
When compiling with -Ycheck:all
, the compiler crashes; otherwise, the code compiles. It seems that the transparent inline
method is crucial to produce the crash.
Error and Stack Trace
*** error while checking Test.scala after phase inlining ***
java.util.NoSuchElementException: head of empty list while running Ycheck on Test.scala
java.util.NoSuchElementException: head of empty list while compiling Test.scala, TestMacro.scala
[error] ## Exception when compiling 2 sources
[error] java.util.NoSuchElementException: head of empty list
[error] scala.collection.immutable.Nil$.head(List.scala:662)
[error] scala.collection.immutable.Nil$.head(List.scala:661)
[error] dotty.tools.dotc.transform.YCheckPositions$$anon$1.traverse(YCheckPositions.scala:45)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1620)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1661)
[error] dotty.tools.dotc.transform.YCheckPositions$$anon$1.traverse(YCheckPositions.scala:53)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.fold$1(Trees.scala:1532)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.apply(Trees.scala:1534)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1627)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1661)
[error] dotty.tools.dotc.transform.YCheckPositions$$anon$1.traverse(YCheckPositions.scala:53)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1624)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1661)
[error] dotty.tools.dotc.transform.YCheckPositions$$anon$1.traverse(YCheckPositions.scala:53)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1660)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.fold$1(Trees.scala:1532)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.apply(Trees.scala:1534)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1633)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1661)
[error] dotty.tools.dotc.transform.YCheckPositions$$anon$1.traverse(YCheckPositions.scala:53)
[error] dotty.tools.dotc.transform.YCheckPositions.checkPostCondition(YCheckPositions.scala:58)
[error] dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted$$anonfun$1(TreeChecker.scala:412)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.immutable.List.foreach(List.scala:333)
[error] dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:412)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:3077)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:3081)
[error] dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:378)
[error] dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3193)
[error] dotty.tools.dotc.transform.TreeChecker.check(TreeChecker.scala:126)
[error] dotty.tools.dotc.transform.TreeChecker.run(TreeChecker.scala:106)
[error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:324)
[error] scala.collection.immutable.List.map(List.scala:246)
[error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:328)
[error] dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:247)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1321)
[error] dotty.tools.dotc.Run.runPhases$1(Run.scala:263)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:271)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:280)
[error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:280)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:201)
[error] dotty.tools.dotc.Driver.finish(Driver.scala:56)
[error] dotty.tools.dotc.Driver.doCompile(Driver.scala:36)
[error] dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:88)
[error] dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22)
Note that I'm not entirely certain whether extracting a subtree of an Inlined
node using Inlined(_, _, Block(List(Apply(_, List(rhs))), _))
is legal, but I think it should be (how else would you get the tree to process it further).