diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index a93e010ddc34..6e68ac1a2de3 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2529,7 +2529,12 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end StringConstantTypeTest object StringConstant extends StringConstantModule: - def apply(x: String): StringConstant = dotc.core.Constants.Constant(x) + def apply(x: String): StringConstant = + require(x != null, "value of StringConstant cannot be `null`") + // A `null` constant must be represented as a `NullConstant`, c.f. a + // constant with `tag == NullTag`, which is not a `StringConstant`. + // See issue 23008. + dotc.core.Constants.Constant(x) def unapply(constant: StringConstant): Some[String] = Some(constant.stringValue) end StringConstant diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index a96785ce2741..009f1c28fbd9 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -3640,7 +3640,10 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Methods of the module object `val StringConstant` */ trait StringConstantModule { this: StringConstant.type => - /** Create a constant String value */ + /** Create a constant String value + * + * @throw `IllegalArgumentException` if the argument is `null` + */ def apply(x: String): StringConstant /** Match String value constant and extract its value */ def unapply(constant: StringConstant): Some[String] diff --git a/tests/neg-macros/i23008.check b/tests/neg-macros/i23008.check new file mode 100644 index 000000000000..c48fdb2fe6fc --- /dev/null +++ b/tests/neg-macros/i23008.check @@ -0,0 +1,21 @@ + +-- Error: tests/neg-macros/i23008/Test_2.scala:1:24 -------------------------------------------------------------------- +1 |@main def Test = Macros.buildString // error + | ^^^^^^^^^^^^^^^^^^ + | Exception occurred while executing macro expansion. + | java.lang.IllegalArgumentException: requirement failed: value of StringConstant cannot be `null` + | at scala.Predef$.require(Predef.scala:337) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2533) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2532) + | at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:80) + | at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:78) + | at scala.quoted.Expr$.apply(Expr.scala:70) + | at Macros$.buildStringCode(Macro_1.scala:9) + | + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Macro_1.scala:4 +4 | inline def buildString = ${buildStringCode} + | ^^^^^^^^^^^^^^^^^^ + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i23008/Macro_1.scala b/tests/neg-macros/i23008/Macro_1.scala new file mode 100644 index 000000000000..67bd091cd9f3 --- /dev/null +++ b/tests/neg-macros/i23008/Macro_1.scala @@ -0,0 +1,11 @@ +import scala.quoted.* + +object Macros { + inline def buildString = ${buildStringCode} + + def buildStringCode(using Quotes): Expr[String] = { + import quotes.reflect.* + val str: String = null + Expr(str) + } +} diff --git a/tests/neg-macros/i23008/Test_2.scala b/tests/neg-macros/i23008/Test_2.scala new file mode 100644 index 000000000000..5ebf2715cf14 --- /dev/null +++ b/tests/neg-macros/i23008/Test_2.scala @@ -0,0 +1 @@ +@main def Test = Macros.buildString // error