From 693b818f9fc9d301acb166d6f7cbeb5b32a9ebbb Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 1 Dec 2020 17:36:34 +0100 Subject: [PATCH 1/2] Patch implementation of `Const.unapply` * Make sure the extrators does not match classes. This should be done using reflection. * Do not match `'{null}` to avoid accidental NPEs. * Do not match `'{}` as there is no value to extract. ```diff - case Const(null) => + case '{null} => - case Const(()) => + case '{} => ``` We specialize use the old, faster, implemtation for `Unliftable` as there it it correct by construction of the available `Unliftable`s. --- .../src-bootstrapped/scala/quoted/Unliftable.scala | 11 ++++++++++- library/src/scala/quoted/Const.scala | 7 ++++++- .../tasty-extractors-constants-1/quoted_1.scala | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/library/src-bootstrapped/scala/quoted/Unliftable.scala b/library/src-bootstrapped/scala/quoted/Unliftable.scala index 7aab27747cf9..06219607a3f2 100644 --- a/library/src-bootstrapped/scala/quoted/Unliftable.scala +++ b/library/src-bootstrapped/scala/quoted/Unliftable.scala @@ -80,7 +80,16 @@ object Unliftable { /** Lift a quoted primitive value `'{ x }` into `x` */ private class PrimitiveUnliftable[T <: Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String] extends Unliftable[T] { - def fromExpr(x: Expr[T]) = Const.unapply(x) + def fromExpr(expr: Expr[T]) = + import quotes.reflect._ + def rec(tree: Term): Option[T] = tree match { + case Literal(c) => Some(c.value.asInstanceOf[T]) + case Block(Nil, e) => rec(e) + case Typed(e, _) => rec(e) + case Inlined(_, Nil, e) => rec(e) + case _ => None + } + rec(Term.of(expr)) } /** Default unliftable for Option diff --git a/library/src/scala/quoted/Const.scala b/library/src/scala/quoted/Const.scala index 574238cb5f9f..2ab8fecccffe 100644 --- a/library/src/scala/quoted/Const.scala +++ b/library/src/scala/quoted/Const.scala @@ -21,7 +21,12 @@ object Const { def unapply[T](expr: Expr[T])(using Quotes): Option[T] = { import quotes.reflect._ def rec(tree: Term): Option[T] = tree match { - case Literal(c) => Some(c.value.asInstanceOf[T]) + case Literal(c) => + c match + case Constant.Null() => None + case Constant.Unit() => None + case Constant.ClassOf(_) => None + case _ => Some(c.value.asInstanceOf[T]) case Block(Nil, e) => rec(e) case Typed(e, _) => rec(e) case Inlined(_, Nil, e) => rec(e) diff --git a/tests/run-macros/tasty-extractors-constants-1/quoted_1.scala b/tests/run-macros/tasty-extractors-constants-1/quoted_1.scala index 7bd6caecd85e..8f53d7a39e3c 100644 --- a/tests/run-macros/tasty-extractors-constants-1/quoted_1.scala +++ b/tests/run-macros/tasty-extractors-constants-1/quoted_1.scala @@ -14,7 +14,7 @@ object Macros { Expr(3) match { case Const(n) => stagedPrintln(n) } '{4} match { case Const(n) => stagedPrintln(n) } '{"abc"} match { case Const(n) => stagedPrintln(n) } - '{null} match { case Const(n) => stagedPrintln(n) } + '{null} match { case '{null} => stagedPrintln(null) } '{new Object} match { case Const(n) => println(n); case _ => stagedPrintln("OK") } From 941410ddd67a8b8caf6e7d8d8bee57cf88ae398f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 1 Dec 2020 18:09:45 +0100 Subject: [PATCH 2/2] Do not match `null` in `StringUnliftable` --- library/src-bootstrapped/scala/quoted/Unliftable.scala | 2 +- tests/run-staging/unliftables.check | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src-bootstrapped/scala/quoted/Unliftable.scala b/library/src-bootstrapped/scala/quoted/Unliftable.scala index 06219607a3f2..1df394dadfa6 100644 --- a/library/src-bootstrapped/scala/quoted/Unliftable.scala +++ b/library/src-bootstrapped/scala/quoted/Unliftable.scala @@ -83,7 +83,7 @@ object Unliftable { def fromExpr(expr: Expr[T]) = import quotes.reflect._ def rec(tree: Term): Option[T] = tree match { - case Literal(c) => Some(c.value.asInstanceOf[T]) + case Literal(c) if c.value != null => Some(c.value.asInstanceOf[T]) case Block(Nil, e) => rec(e) case Typed(e, _) => rec(e) case Inlined(_, Nil, e) => rec(e) diff --git a/tests/run-staging/unliftables.check b/tests/run-staging/unliftables.check index 4a3993484692..b28424f347f4 100644 --- a/tests/run-staging/unliftables.check +++ b/tests/run-staging/unliftables.check @@ -38,7 +38,7 @@ Some(Some(3)) Some(None) Some(Some(3)) Some(Some(3)) -Some(None) +None Some(Left(1)) Some(Right(2))