Skip to content

Commit 1f529ef

Browse files
committed
Suspend macros when class not found during macro expansion
1 parent 4de288b commit 1f529ef

File tree

6 files changed

+49
-23
lines changed

6 files changed

+49
-23
lines changed

compiler/src/dotty/tools/dotc/transform/Splicer.scala

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ object Splicer {
4747
interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
4848
}
4949
catch {
50+
case ex: CompilationUnit.SuspendException =>
51+
throw ex
5052
case ex: StopInterpretation =>
5153
ctx.error(ex.msg, ex.pos)
5254
EmptyTree
@@ -348,19 +350,26 @@ object Splicer {
348350
sw.write("\n")
349351
throw new StopInterpretation(sw.toString, pos)
350352
case ex: InvocationTargetException =>
351-
val sw = new StringWriter()
352-
sw.write("Exception occurred while executing macro expansion.\n")
353-
val targetException = ex.getTargetException
354-
if (!ctx.settings.Ydebug.value) {
355-
val end = targetException.getStackTrace.lastIndexWhere { x =>
356-
x.getClassName == method.getDeclaringClass.getCanonicalName && x.getMethodName == method.getName
357-
}
358-
val shortStackTrace = targetException.getStackTrace.take(end + 1)
359-
targetException.setStackTrace(shortStackTrace)
353+
ex.getTargetException match {
354+
case targetException: NoClassDefFoundError => // FIXME check that the class is beeining compiled now
355+
val className = targetException.getMessage
356+
if (ctx.settings.XprintSuspension.value)
357+
ctx.echo(i"suspension triggered by NoClassDefFoundError($className)", pos) // TODO improve message
358+
ctx.compilationUnit.suspend() // this throws a SuspendException
359+
case targetException =>
360+
val sw = new StringWriter()
361+
sw.write("Exception occurred while executing macro expansion.\n")
362+
if (!ctx.settings.Ydebug.value) {
363+
val end = targetException.getStackTrace.lastIndexWhere { x =>
364+
x.getClassName == method.getDeclaringClass.getCanonicalName && x.getMethodName == method.getName
365+
}
366+
val shortStackTrace = targetException.getStackTrace.take(end + 1)
367+
targetException.setStackTrace(shortStackTrace)
368+
}
369+
targetException.printStackTrace(new PrintWriter(sw))
370+
sw.write("\n")
371+
throw new StopInterpretation(sw.toString, pos)
360372
}
361-
targetException.printStackTrace(new PrintWriter(sw))
362-
sw.write("\n")
363-
throw new StopInterpretation(sw.toString, pos)
364373
}
365374

366375
/** List of classes of the parameters of the signature of `sym` */

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,9 +1242,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
12421242
if dependencies.nonEmpty then
12431243
for sym <- dependencies do
12441244
if ctx.compilationUnit.source.file == sym.associatedFile then
1245-
ctx.error(em"Cannot call macro $sym defined in the same source file", body.sourcePos)
1245+
ctx.error(em"Cannot call macro $sym defined in the same source file", call.sourcePos)
12461246
if (ctx.settings.XprintSuspension.value)
1247-
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", body.sourcePos)
1247+
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", call.sourcePos)
12481248
ctx.compilationUnit.suspend() // this throws a SuspendException
12491249

12501250
val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx1)
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
-- Error: tests/neg-macros/macros-in-same-project-4/Bar.scala:5:13 -----------------------------------------------------
2-
5 | Foo.myMacro() // error
3-
| ^^^^^^^^^^^^^
4-
|Failed to expand macro. This macro depends on an implementation that is defined in the same project and not yet compiled.
5-
|In particular method myMacro depends on method aMacroImplementation.
6-
|
7-
|Moving method aMacroImplementation to a different project would fix this.
8-
| This location is in code that was inlined at Bar.scala:5
1+
Cyclic macro dependencies in tests/neg-macros/macros-in-same-project-4/Bar.scala.
2+
Compilation stopped since no further progress can be made.
3+
4+
To fix this, place macros in one set of files and their callers in another.
5+
6+
Compiling with -Xprint-suspension gives more information.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
// nopos-error
12
import scala.quoted._
23

34
object Bar {
45

5-
Foo.myMacro() // error
6+
Foo.myMacro()
67

78
def hello()(given QuoteContext): Expr[Unit] = '{ println("Hello") }
89
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.quoted._
2+
3+
object Bar {
4+
5+
Foo.myMacro() // error
6+
7+
def aMacroImplementation(given QuoteContext): Expr[Unit] = Bar.hello()
8+
9+
def hello()(given QuoteContext): Expr[Unit] = '{ println("Hello") }
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted._
2+
import Bar.aMacroImplementation
3+
4+
object Foo {
5+
6+
inline def myMacro(): Unit = ${ aMacroImplementation }
7+
8+
}

0 commit comments

Comments
 (0)