From 1f529efda24939be45e1ff208f3b09f4ceaf59d4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 30 Sep 2019 10:23:30 +0200 Subject: [PATCH] Suspend macros when class not found during macro expansion --- .../dotty/tools/dotc/transform/Splicer.scala | 33 ++++++++++++------- .../src/dotty/tools/dotc/typer/Inliner.scala | 4 +-- .../neg-macros/macros-in-same-project-4.check | 14 ++++---- .../macros-in-same-project-4/Bar.scala | 3 +- .../macros-in-same-project-5/Bar.scala | 10 ++++++ .../macros-in-same-project-5/Foo.scala | 8 +++++ 6 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 tests/neg-macros/macros-in-same-project-5/Bar.scala create mode 100644 tests/neg-macros/macros-in-same-project-5/Foo.scala diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index bd988422541f..9d8d283caa9c 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -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 @@ -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` */ diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index fa37a015dc05..6f05a502db22 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -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) diff --git a/tests/neg-macros/macros-in-same-project-4.check b/tests/neg-macros/macros-in-same-project-4.check index 5cdc12b31cb9..79c78fd0fb7f 100644 --- a/tests/neg-macros/macros-in-same-project-4.check +++ b/tests/neg-macros/macros-in-same-project-4.check @@ -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. diff --git a/tests/neg-macros/macros-in-same-project-4/Bar.scala b/tests/neg-macros/macros-in-same-project-4/Bar.scala index de9ec400b49b..da86189bb201 100644 --- a/tests/neg-macros/macros-in-same-project-4/Bar.scala +++ b/tests/neg-macros/macros-in-same-project-4/Bar.scala @@ -1,8 +1,9 @@ +// nopos-error import scala.quoted._ object Bar { - Foo.myMacro() // error + Foo.myMacro() def hello()(given QuoteContext): Expr[Unit] = '{ println("Hello") } } diff --git a/tests/neg-macros/macros-in-same-project-5/Bar.scala b/tests/neg-macros/macros-in-same-project-5/Bar.scala new file mode 100644 index 000000000000..b3b6e792a984 --- /dev/null +++ b/tests/neg-macros/macros-in-same-project-5/Bar.scala @@ -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") } +} diff --git a/tests/neg-macros/macros-in-same-project-5/Foo.scala b/tests/neg-macros/macros-in-same-project-5/Foo.scala new file mode 100644 index 000000000000..b50e017cc1c5 --- /dev/null +++ b/tests/neg-macros/macros-in-same-project-5/Foo.scala @@ -0,0 +1,8 @@ +import scala.quoted._ +import Bar.aMacroImplementation + +object Foo { + + inline def myMacro(): Unit = ${ aMacroImplementation } + +}