From 164a8edc59d4e62bb4de99e15d1e986c16e2a503 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Tue, 26 Nov 2024 17:21:14 +0100 Subject: [PATCH] Add a check for correct Array shape in quotes.reflect.ClassOfConstant --- .../scala/quoted/runtime/impl/QuotesImpl.scala | 12 +++++++++++- tests/neg-macros/i21916.check | 15 +++++++++++++++ tests/neg-macros/i21916/Macro_1.scala | 9 +++++++++ tests/neg-macros/i21916/Test_2.scala | 1 + 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/neg-macros/i21916.check create mode 100644 tests/neg-macros/i21916/Macro_1.scala create mode 100644 tests/neg-macros/i21916/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 22be293c3562..2559334fa996 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2519,7 +2519,17 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object ClassOfConstant extends ClassOfConstantModule: def apply(x: TypeRepr): ClassOfConstant = - // TODO check that the type is a valid class when creating this constant or let Ycheck do it? + // We only check if the supplied TypeRepr is valid if it contains an Array, + // as so far only that Array could cause issues + def correctTypeApplicationForArray(typeRepr: TypeRepr): Boolean = + val isArray = typeRepr.typeSymbol != dotc.core.Symbols.defn.ArrayClass + typeRepr match + case AppliedType(_, Nil) => isArray + case _ => isArray + xCheckMacroAssert( + correctTypeApplicationForArray(x), + "Illegal empty Array type constructor. Please supply a type parameter." + ) dotc.core.Constants.Constant(x) def unapply(constant: ClassOfConstant): Some[TypeRepr] = Some(constant.typeValue) end ClassOfConstant diff --git a/tests/neg-macros/i21916.check b/tests/neg-macros/i21916.check new file mode 100644 index 000000000000..b07bc5736bd9 --- /dev/null +++ b/tests/neg-macros/i21916.check @@ -0,0 +1,15 @@ + +-- Error: tests/neg-macros/i21916/Test_2.scala:1:33 -------------------------------------------------------------------- +1 |@main def Test: Unit = Macro.test() // error + | ^^^^^^^^^^^^ + | Exception occurred while executing macro expansion. + | java.lang.AssertionError: Illegal empty Array type constructor. Please supply a type parameter. + | at Macro$.testImpl(Macro_1.scala:8) + | + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Macro_1.scala:3 +3 | inline def test() = ${testImpl} + | ^^^^^^^^^^^ + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i21916/Macro_1.scala b/tests/neg-macros/i21916/Macro_1.scala new file mode 100644 index 000000000000..78af2cde2963 --- /dev/null +++ b/tests/neg-macros/i21916/Macro_1.scala @@ -0,0 +1,9 @@ +import scala.quoted._ +object Macro: + inline def test() = ${testImpl} + def testImpl(using Quotes): Expr[Any] = { + import quotes.reflect._ + val tpe = TypeRepr.of[Array[Byte]] match + case AppliedType(tycons, _) => tycons + Literal(ClassOfConstant(tpe)).asExpr + } diff --git a/tests/neg-macros/i21916/Test_2.scala b/tests/neg-macros/i21916/Test_2.scala new file mode 100644 index 000000000000..da8bf436a33c --- /dev/null +++ b/tests/neg-macros/i21916/Test_2.scala @@ -0,0 +1 @@ +@main def Test: Unit = Macro.test() // error