Skip to content

Commit

Permalink
Suspend macros when class not found during macro expansion
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Sep 30, 2019
1 parent 4de288b commit 1f529ef
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 23 deletions.
33 changes: 21 additions & 12 deletions compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ object Splicer {
interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
}
catch {
case ex: CompilationUnit.SuspendException =>
throw ex
case ex: StopInterpretation =>
ctx.error(ex.msg, ex.pos)
EmptyTree
Expand Down Expand Up @@ -348,19 +350,26 @@ object Splicer {
sw.write("\n")
throw new StopInterpretation(sw.toString, pos)
case ex: InvocationTargetException =>
val sw = new StringWriter()
sw.write("Exception occurred while executing macro expansion.\n")
val targetException = ex.getTargetException
if (!ctx.settings.Ydebug.value) {
val end = targetException.getStackTrace.lastIndexWhere { x =>
x.getClassName == method.getDeclaringClass.getCanonicalName && x.getMethodName == method.getName
}
val shortStackTrace = targetException.getStackTrace.take(end + 1)
targetException.setStackTrace(shortStackTrace)
ex.getTargetException match {
case targetException: NoClassDefFoundError => // FIXME check that the class is beeining compiled now
val className = targetException.getMessage
if (ctx.settings.XprintSuspension.value)
ctx.echo(i"suspension triggered by NoClassDefFoundError($className)", pos) // TODO improve message
ctx.compilationUnit.suspend() // this throws a SuspendException
case targetException =>
val sw = new StringWriter()
sw.write("Exception occurred while executing macro expansion.\n")
if (!ctx.settings.Ydebug.value) {
val end = targetException.getStackTrace.lastIndexWhere { x =>
x.getClassName == method.getDeclaringClass.getCanonicalName && x.getMethodName == method.getName
}
val shortStackTrace = targetException.getStackTrace.take(end + 1)
targetException.setStackTrace(shortStackTrace)
}
targetException.printStackTrace(new PrintWriter(sw))
sw.write("\n")
throw new StopInterpretation(sw.toString, pos)
}
targetException.printStackTrace(new PrintWriter(sw))
sw.write("\n")
throw new StopInterpretation(sw.toString, pos)
}

/** List of classes of the parameters of the signature of `sym` */
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1242,9 +1242,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
if dependencies.nonEmpty then
for sym <- dependencies do
if ctx.compilationUnit.source.file == sym.associatedFile then
ctx.error(em"Cannot call macro $sym defined in the same source file", body.sourcePos)
ctx.error(em"Cannot call macro $sym defined in the same source file", call.sourcePos)
if (ctx.settings.XprintSuspension.value)
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", body.sourcePos)
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", call.sourcePos)
ctx.compilationUnit.suspend() // this throws a SuspendException

val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx1)
Expand Down
14 changes: 6 additions & 8 deletions tests/neg-macros/macros-in-same-project-4.check
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
-- Error: tests/neg-macros/macros-in-same-project-4/Bar.scala:5:13 -----------------------------------------------------
5 | Foo.myMacro() // error
| ^^^^^^^^^^^^^
|Failed to expand macro. This macro depends on an implementation that is defined in the same project and not yet compiled.
|In particular method myMacro depends on method aMacroImplementation.
|
|Moving method aMacroImplementation to a different project would fix this.
| This location is in code that was inlined at Bar.scala:5
Cyclic macro dependencies in tests/neg-macros/macros-in-same-project-4/Bar.scala.
Compilation stopped since no further progress can be made.

To fix this, place macros in one set of files and their callers in another.

Compiling with -Xprint-suspension gives more information.
3 changes: 2 additions & 1 deletion tests/neg-macros/macros-in-same-project-4/Bar.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// nopos-error
import scala.quoted._

object Bar {

Foo.myMacro() // error
Foo.myMacro()

def hello()(given QuoteContext): Expr[Unit] = '{ println("Hello") }
}
10 changes: 10 additions & 0 deletions tests/neg-macros/macros-in-same-project-5/Bar.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import scala.quoted._

object Bar {

Foo.myMacro() // error

def aMacroImplementation(given QuoteContext): Expr[Unit] = Bar.hello()

def hello()(given QuoteContext): Expr[Unit] = '{ println("Hello") }
}
8 changes: 8 additions & 0 deletions tests/neg-macros/macros-in-same-project-5/Foo.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import scala.quoted._
import Bar.aMacroImplementation

object Foo {

inline def myMacro(): Unit = ${ aMacroImplementation }

}

0 comments on commit 1f529ef

Please sign in to comment.