diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 3877c36cdb59..3e667908844e 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -36,7 +36,11 @@ object Splicer { val liftedArgs = getLiftedArgs(call, bindings) val interpreter = new Interpreter(pos, classLoader) val interpreted = interpreter.interpretCallToSymbol[Seq[Any] => Object](call.symbol) - interpreted.flatMap(lambda => evaluateLambda(lambda, liftedArgs, pos)).fold(tree)(PickledQuotes.quotedExprToTree) + evaluateMacro(pos) { + // Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree + val evaluated = interpreted.map(lambda => lambda(liftedArgs).asInstanceOf[scala.quoted.Expr[Nothing]]) + evaluated.fold(tree)(PickledQuotes.quotedExprToTree) + } } /** Given the inline code and bindings, compute the lifted arguments that will be used to execute the macro @@ -72,20 +76,21 @@ object Splicer { liftArgs(call.symbol.info, allArgs(call, Nil)) } - private def evaluateLambda(lambda: Seq[Any] => Object, args: Seq[Any], pos: Position)(implicit ctx: Context): Option[scala.quoted.Expr[Nothing]] = { - try Some(lambda(args).asInstanceOf[scala.quoted.Expr[Nothing]]) + /* Evaluate the code in the macro and handle exceptions durring evaluation */ + private def evaluateMacro(pos: Position)(code: => Tree)(implicit ctx: Context): Tree = { + try code catch { case ex: scala.quoted.QuoteError => ctx.error(ex.getMessage, pos) - None + EmptyTree case NonFatal(ex) => val msg = s"""Failed to evaluate inlined quote. - | Caused by: ${ex.getMessage} - | ${ex.getStackTrace.takeWhile(_.getClassName != "dotty.tools.dotc.transform.Splicer$").init.mkString("\n ")} + | Caused by ${ex.getClass}: ${if (ex.getMessage == null) "" else ex.getMessage} + | ${ex.getStackTrace.takeWhile(_.getClassName != "dotty.tools.dotc.transform.Splicer$").init.mkString("\n ")} """.stripMargin ctx.error(msg, pos) - None + EmptyTree } } diff --git a/tests/neg/quote-error-2/Macro_1.scala b/tests/neg/quote-error-2/Macro_1.scala new file mode 100644 index 000000000000..0cce8284f871 --- /dev/null +++ b/tests/neg/quote-error-2/Macro_1.scala @@ -0,0 +1,12 @@ +import quoted._ + +object Macro_1 { + inline def foo(inline b: Boolean): Unit = ~fooImpl(b) + def fooImpl(b: Boolean): Expr[Unit] = + '(println(~msg(b))) + + def msg(b: Boolean): Expr[String] = + if (b) '("foo(true)") + else QuoteError("foo cannot be called with false") + +} diff --git a/tests/neg/quote-error-2/Test_2.scala b/tests/neg/quote-error-2/Test_2.scala new file mode 100644 index 000000000000..fccefeaad1f3 --- /dev/null +++ b/tests/neg/quote-error-2/Test_2.scala @@ -0,0 +1,6 @@ +import Macro_1._ + +object Test_2 { + foo(true) + foo(false) // error: foo cannot be called with false +}