From c84810936bb7a40aa151b9effbc48e06ed9ee9b0 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 5 Mar 2024 11:22:32 +0000 Subject: [PATCH 1/2] Avoid crash after StopMacroExpansion When a splice throws a StopMacroExpansion, it's replaced by an EmptyTree, which has NoType. Which means you can't cast it, as you can't call .asInstanceOf on it. So handle this before calling ensureConforms. [Cherry-picked 44aa3c62bba824968c307abf4737f2f22ec841e5] --- compiler/src/dotty/tools/dotc/inlines/Inlines.scala | 8 ++++---- tests/neg-macros/i19851/Macro_1.scala | 9 +++++++++ tests/neg-macros/i19851/Test_2.scala | 3 +++ 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 tests/neg-macros/i19851/Macro_1.scala create mode 100644 tests/neg-macros/i19851/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index 89b70711db66..74629b75b841 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -449,14 +449,14 @@ object Inlines: // Take care that only argument bindings go into `bindings`, since positions are // different for bindings from arguments and bindings from body. - val res = tpd.Inlined(call, bindings, expansion) + val inlined = tpd.Inlined(call, bindings, expansion) - if !hasOpaqueProxies then res + if !hasOpaqueProxies || !inlined.tpe.exists then inlined else val target = - if inlinedMethod.is(Transparent) then call.tpe & res.tpe + if inlinedMethod.is(Transparent) then call.tpe & inlined.tpe else call.tpe - res.ensureConforms(target) + inlined.ensureConforms(target) // Make sure that the sealing with the declared type // is type correct. Without it we might get problems since the // expression's type is the opaque alias but the call's type is diff --git a/tests/neg-macros/i19851/Macro_1.scala b/tests/neg-macros/i19851/Macro_1.scala new file mode 100644 index 000000000000..33b2aa2e2849 --- /dev/null +++ b/tests/neg-macros/i19851/Macro_1.scala @@ -0,0 +1,9 @@ +import scala.quoted.* + +opaque type Box[A] = Any +object Box: + transparent inline def pack[A]: Nothing => Box[A] = ${ packImpl[A] } + + private def packImpl[A](using Quotes, Type[A]): Expr[Nothing => Box[A]] = + import quotes.reflect.* + report.errorAndAbort("Not implemented") diff --git a/tests/neg-macros/i19851/Test_2.scala b/tests/neg-macros/i19851/Test_2.scala new file mode 100644 index 000000000000..ab2f01a7019a --- /dev/null +++ b/tests/neg-macros/i19851/Test_2.scala @@ -0,0 +1,3 @@ +class Test: + def t1: Unit = + Box.pack[Int] // error From 37abd28bc362f46d99a1d8cbc8fefa151265e65f Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 5 Mar 2024 12:33:12 +0000 Subject: [PATCH 2/2] Use ??? instead of EmptyTree for StopMacroExpansion. [Cherry-picked 0fe04905dec86b6d58b44cee824ed4a4a8c8b59e] --- compiler/src/dotty/tools/dotc/inlines/Inlines.scala | 2 +- compiler/src/dotty/tools/dotc/transform/Splicer.scala | 2 +- tests/neg-macros/i9014b.check | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index 74629b75b841..61e2a58a0176 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -451,7 +451,7 @@ object Inlines: // different for bindings from arguments and bindings from body. val inlined = tpd.Inlined(call, bindings, expansion) - if !hasOpaqueProxies || !inlined.tpe.exists then inlined + if !hasOpaqueProxies then inlined else val target = if inlinedMethod.is(Transparent) then call.tpe & inlined.tpe diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 1f7b65ba66a6..916b102dc692 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -72,7 +72,7 @@ object Splicer { if !ctx.reporter.hasErrors then report.error("Macro expansion was aborted by the macro without any errors reported. Macros should issue errors to end-users when aborting a macro expansion with StopMacroExpansion.", splicePos) // errors have been emitted - EmptyTree + ref(defn.Predef_undefined).withType(ErrorType(em"macro expansion was stopped")) case ex: StopInterpretation => report.error(ex.msg, ex.pos) ref(defn.Predef_undefined).withType(ErrorType(ex.msg)) diff --git a/tests/neg-macros/i9014b.check b/tests/neg-macros/i9014b.check index de0be2d5c1fa..4098bccf462b 100644 --- a/tests/neg-macros/i9014b.check +++ b/tests/neg-macros/i9014b.check @@ -7,4 +7,4 @@ | | given_Bar | - | But given instance given_Bar does not match type Bar. + | But macro expansion was stopped.