diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 66622a253a93..2e63b7ee00f6 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2092,7 +2092,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler given ConstantMethods: ConstantMethods with extension (self: Constant) def value: Any = self.value - def show: String = Extractors.showConstant(using QuotesImpl.this)(self) + def show(using printer: Printer[Constant]): String = printer.show(self) end extension end ConstantMethods @@ -2774,6 +2774,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def show(tpe: TypeRepr): String = Extractors.showType(using QuotesImpl.this)(tpe) + lazy val ConstantCode: Printer[Constant] = new Printer[Constant]: + def show(const: Constant): String = + const.show(using ctx.fresh.setSetting(ctx.settings.color, "never")) + + lazy val ConstantStructure: Printer[Constant] = new Printer[Constant]: + def show(const: Constant): String = + Extractors.showConstant(using QuotesImpl.this)(const) + end Printer end reflect diff --git a/library/src-bootstrapped/scala/quoted/FromExpr.scala b/library/src-bootstrapped/scala/quoted/FromExpr.scala index 6f57c542af50..2bdb510c82d8 100644 --- a/library/src-bootstrapped/scala/quoted/FromExpr.scala +++ b/library/src-bootstrapped/scala/quoted/FromExpr.scala @@ -29,69 +29,100 @@ object FromExpr { * - Unlifts `'{false}` into `Some(false)` * - Otherwise unlifts to `None` */ - given BooleanFromExpr[T <: Boolean]: FromExpr[T] = new PrimitiveFromExpr + given BooleanFromExpr[T <: Boolean]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for BooleanConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[Byte]` * - Unlifts `'{n}` into `Some(n)` for a literal `n` of type `Byte` * - Otherwise unlifts to `None` */ - given ByteFromExpr[T <: Byte]: FromExpr[T] = new PrimitiveFromExpr + given ByteFromExpr[T <: Byte]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for ByteConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[Short]` * - Unlifts `'{n}` into `Some(n)` for a literal `n` of type `Short` * - Otherwise unlifts to `None` */ - given ShortFromExpr[T <: Short]: FromExpr[T] = new PrimitiveFromExpr + given ShortFromExpr[T <: Short]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for ShortConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[Int]` * - Unlifts `'{n}` into `Some(n)` for a literal `n` of type `Int` * - Otherwise unlifts to `None` */ - given IntFromExpr[T <: Int]: FromExpr[T] = new PrimitiveFromExpr + given IntFromExpr[T <: Int]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for IntConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[Long]` * - Unlifts `'{n}` into `Some(n)` for a literal `n` of type `Long` * - Otherwise unlifts to `None` */ - given LongFromExpr[T <: Long]: FromExpr[T] = new PrimitiveFromExpr + given LongFromExpr[T <: Long]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for LongConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[Float]` * - Unlifts `'{n}` into `Some(n)` for a literal `n` of type `Float` * - Otherwise unlifts to `None` */ - given FloatFromExpr[T <: Float]: FromExpr[T] = new PrimitiveFromExpr + given FloatFromExpr[T <: Float]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for FloatConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[Double]` * - Unlifts `'{n}` into `Some(n)` for a literal `n` of type `Double` * - Otherwise unlifts to `None` */ - given DoubleFromExpr[T <: Double]: FromExpr[T] = new PrimitiveFromExpr + given DoubleFromExpr[T <: Double]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for DoubleConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[Char]` * - Unlifts `'{c}` into `Some(c)` for a literal `c` of type `Char` * - Otherwise unlifts to `None` */ - given CharFromExpr[T <: Char]: FromExpr[T] = new PrimitiveFromExpr + given CharFromExpr[T <: Char]: FromExpr[T] with + def unapply(expr: Expr[T])(using Quotes) = + import quotes.reflect._ + for CharConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] /** Default implementation of `FromExpr[String]` * - Unlifts `'{str}` into `Some(str)` for a literal `str` of type `String` * - Otherwise unlifts to `None` */ - given StringFromExpr[T <: String]: FromExpr[T] = new PrimitiveFromExpr - - /** Lift a quoted primitive value `'{ x }` into `x` */ - private class PrimitiveFromExpr[T <: Boolean | Byte | Short | Int | Long | Float | Double | Char | String] extends FromExpr[T] { + given StringFromExpr[T <: String]: FromExpr[T] with def unapply(expr: Expr[T])(using Quotes) = import quotes.reflect._ - def rec(tree: Term): Option[T] = tree match { - 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) - case _ => None - } - rec(expr.asTerm) - } + for StringConstant(v) <- nestedConstant(expr.asTerm) + yield v.asInstanceOf[T] + + private def nestedConstant(using Quotes)(tree: quotes.reflect.Term): Option[quotes.reflect.Constant] = + import quotes.reflect._ + tree match + case Literal(c) => Some(c) + case Block(Nil, e) => nestedConstant(e) + case Typed(e, _) => nestedConstant(e) + case Inlined(_, Nil, e) => nestedConstant(e) + case _ => None /** Default implementation of `FromExpr[Option]` * - Unlifts `'{Some(x)}` into `Some(Some(x))` if `x` is unliftable diff --git a/library/src/scala/quoted/Const.scala b/library/src/scala/quoted/Const.scala index 7b65f5118a09..47fc62507a85 100644 --- a/library/src/scala/quoted/Const.scala +++ b/library/src/scala/quoted/Const.scala @@ -26,7 +26,14 @@ object Const { case Literal(c) => c match case NullConstant() | UnitConstant() | ClassOfConstant(_) => None - case _ => Some(c.value.asInstanceOf[T]) + case BooleanConstant(x) => Some(x.asInstanceOf[T]) + case ShortConstant(x) => Some(x.asInstanceOf[T]) + case IntConstant(x) => Some(x.asInstanceOf[T]) + case LongConstant(x) => Some(x.asInstanceOf[T]) + case FloatConstant(x) => Some(x.asInstanceOf[T]) + case DoubleConstant(x) => Some(x.asInstanceOf[T]) + case CharConstant(x) => Some(x.asInstanceOf[T]) + case StringConstant(x) => Some(x.asInstanceOf[T]) case Block(Nil, e) => rec(e) case Typed(e, _) => rec(e) case Inlined(_, Nil, e) => rec(e) diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index defdfe940bfb..872b1c825387 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -2754,11 +2754,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Extension methods of `Constant` */ trait ConstantMethods { extension (self: Constant) - /** Returns the value of the constant */ - def value: Any - /** Shows the constant as a String */ - def show: String + def show(using Printer[Constant]): String + end extension } @@ -4113,6 +4111,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Default pinter for `TypeRepr` used when calling `tpe.show` */ given TypeReprPrinter: Printer[TypeRepr] = Printer.TypeReprCode + /** Default pinter for `Constant` used when calling `const.show` */ + given ConstantPrinter: Printer[Constant] = Printer.ConstantCode + /** Module object of `type Printer`. * Contains custom printers such as `TreeCode`, `TreeAnsiCode`, `TreeCases`, `TypeReprCode`, ..., `SymbolFullName` and `FlagsCombination`. */ @@ -4152,6 +4153,11 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => */ def TypeReprStructure: Printer[TypeRepr] + /** Prints the constant in source code. */ + def ConstantCode: Printer[Constant] + + /** Prints a pattern like representation of the `Constant`. */ + def ConstantStructure: Printer[Constant] } } diff --git a/scala3doc/src/dotty/dokka/tasty/BasicSupport.scala b/scala3doc/src/dotty/dokka/tasty/BasicSupport.scala index 91c8f8529765..1bc00cfd5d6a 100644 --- a/scala3doc/src/dotty/dokka/tasty/BasicSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/BasicSupport.scala @@ -18,14 +18,8 @@ trait BasicSupport: val params = annotTerm match case Apply(target, appliedWith) => { appliedWith.flatMap { - case Literal(constant) => Some(Annotation.PrimitiveParameter(None, constant.value match { - case s: String => "\"" + s"$s" + "\"" - case other => other.toString() - })) - case NamedArg(name, Literal(constant)) => Some(Annotation.PrimitiveParameter(Some(name), constant.value match - case s: String => "\"" + s"$s" + "\"" - case other => other.toString() - )) + case Literal(constant) => Some(Annotation.PrimitiveParameter(None, constant.show)) + case NamedArg(name, Literal(constant)) => Some(Annotation.PrimitiveParameter(Some(name), constant.show)) case x @ Select(qual, name) => None case other => Some(Annotation.UnresolvedParameter(None, other.show)) } @@ -33,7 +27,6 @@ trait BasicSupport: Annotation(dri, params) - extension (sym: Symbol) def documentation = sym.docstring match case Some(docstring) => diff --git a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala index 72adc698fa18..32ab6c4083c7 100644 --- a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala @@ -84,10 +84,7 @@ trait TypesSupport: case AndType(left, right) => inner(left) ++ texts(" & ") ++ inner(right) case ByNameType(tpe) => text("=> ") :: inner(tpe) case ConstantType(constant) => - texts(constant.value match - case c: Char => s"'$c'" - case other => other.toString - ) + texts(constant.show) case ThisType(tpe) => inner(tpe) case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeated(annotation) => inner(tpe) :+ text("*") diff --git a/tests/run-custom-args/tasty-interpreter/interpreter/jvm/Interpreter.scala b/tests/run-custom-args/tasty-interpreter/interpreter/jvm/Interpreter.scala index a01c3396c7e1..cab7689a8f51 100644 --- a/tests/run-custom-args/tasty-interpreter/interpreter/jvm/Interpreter.scala +++ b/tests/run-custom-args/tasty-interpreter/interpreter/jvm/Interpreter.scala @@ -83,7 +83,20 @@ class Interpreter[Q <: Quotes & Singleton](using q0: Q) extends TreeInterpreter[ def interpretUnit(): AbstractAny = ().asInstanceOf[Object] - def interpretLiteral(const: Constant): Result = const.value + def interpretLiteral(const: Constant): Result = + const match + case UnitConstant() => () + case NullConstant() => null + case BooleanConstant(v) => v + case ByteConstant(v) => v + case ShortConstant(v) => v + case IntConstant(v) => v + case LongConstant(v) => v + case FloatConstant(v) => v + case DoubleConstant(v) => v + case CharConstant(v) => v + case StringConstant(v) => v + case ClassOfConstant(v) => ??? def interpretIsInstanceOf(o: AbstractAny, tpt: TypeTree): Result = jvmReflection.getClassOf(tpt.symbol).isInstance(o)