Skip to content

Improve Expr.toString and Type.toString #16556

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -197,18 +197,18 @@ object PickledQuotes {
}

def reifyTypeHoleArgs(args: List[Tree])(using Context): List[scala.quoted.Type[?]] =
args.map(arg => new TypeImpl(arg, SpliceScope.getCurrent))
args.map(arg => new TypeImpl(arg))

def reifyExprHoleV1Args(args: List[Tree])(using Context): List[ExprHole.ArgV1] =
args.map { arg =>
if arg.isTerm then (q: Quotes) ?=> new ExprImpl(arg, SpliceScope.getCurrent)
else new TypeImpl(arg, SpliceScope.getCurrent)
if arg.isTerm then (q: Quotes) ?=> new ExprImpl(arg)
else new TypeImpl(arg)
}

def reifyExprHoleV2Args(args: List[Tree])(using Context): List[ExprHole.ArgV2] =
args.map { arg =>
if arg.isTerm then new ExprImpl(arg, SpliceScope.getCurrent)
else new TypeImpl(arg, SpliceScope.getCurrent)
if arg.isTerm then new ExprImpl(arg)
else new TypeImpl(arg)
}

// TASTY picklingtests/pos/quoteTest.scala
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,11 @@ object Splicer {
case Inlined(EmptyTree, _, quoted) => quoted
case _ => quoted
}
new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(quoted1, ctx.owner)).withSpan(quoted1.span), SpliceScope.getCurrent)
new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(quoted1, ctx.owner)).withSpan(quoted1.span))

// Interpret level -1 `Type.of[T]`
case Apply(TypeApply(fn, quoted :: Nil), _) if fn.symbol == defn.QuotedTypeModule_of =>
new TypeImpl(QuoteUtils.changeOwnerOfTree(quoted, ctx.owner), SpliceScope.getCurrent)
new TypeImpl(QuoteUtils.changeOwnerOfTree(quoted, ctx.owner))

case _ =>
super.interpretTree(tree)
Expand Down
9 changes: 6 additions & 3 deletions compiler/src/scala/quoted/runtime/impl/ExprImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package scala.quoted
package runtime.impl

import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context

/** An Expr backed by a tree. Only the current compiler trees are allowed.
*
Expand All @@ -10,7 +11,10 @@ import dotty.tools.dotc.ast.tpd
*
* May contain references to code defined outside this Expr instance.
*/
final class ExprImpl(val tree: tpd.Tree, val scope: Scope) extends Expr[Any] {
final class ExprImpl(val tree: tpd.Tree)(using val ctx: Context) extends Expr[Any]:

def scope: Scope = SpliceScope.getCurrent

override def equals(that: Any): Boolean = that match {
case that: ExprImpl =>
// Expr are wrappers around trees, therefore they are equals if their trees are equal.
Expand All @@ -21,5 +25,4 @@ final class ExprImpl(val tree: tpd.Tree, val scope: Scope) extends Expr[Any] {

override def hashCode(): Int = tree.hashCode()

override def toString: String = "'{ ... }"
}
override def toString(): String = QuotesImpl.showDecompiledTree(tree)
2 changes: 1 addition & 1 deletion compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ object QuoteMatcher {
val matched: Matching = Some(Tuple())

def matched(tree: Tree)(using Context): Matching =
Some(Tuple1(new ExprImpl(tree, SpliceScope.getCurrent)))
Some(Tuple1(new ExprImpl(tree)))

extension (self: Matching)
def asOptionOfTuple: Option[Tuple] = self
Expand Down
16 changes: 8 additions & 8 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
case _ => false
def asExpr: scala.quoted.Expr[Any] =
if self.isExpr then
new ExprImpl(self, SpliceScope.getCurrent)
new ExprImpl(self)
else self match
case TermTypeTest(self) => throw new Exception("Expected an expression. This is a partially applied Term. Try eta-expanding the term first.")
case _ => throw new Exception("Expected a Term but was: " + Printer.TreeStructure.show(self))
Expand Down Expand Up @@ -377,11 +377,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
given TermMethods: TermMethods with
extension (self: Term)
def seal: scala.quoted.Expr[Any] =
if self.isExpr then new ExprImpl(self, SpliceScope.getCurrent)
if self.isExpr then new ExprImpl(self)
else throw new Exception("Cannot seal a partially applied Term. Try eta-expanding the term first.")

def sealOpt: Option[scala.quoted.Expr[Any]] =
if self.isExpr then Some(new ExprImpl(self, SpliceScope.getCurrent))
if self.isExpr then Some(new ExprImpl(self))
else None

def tpe: TypeRepr = self.tpe.widenSkolem
Expand Down Expand Up @@ -1722,7 +1722,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
def seal: scala.quoted.Type[_] = self.asType

def asType: scala.quoted.Type[?] =
new TypeImpl(Inferred(self), SpliceScope.getCurrent)
new TypeImpl(Inferred(self))

def =:=(that: TypeRepr): Boolean = self =:= that
def <:<(that: TypeRepr): Boolean = self <:< that
Expand Down Expand Up @@ -3048,19 +3048,19 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

def unpickleExpr[T](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?]): scala.quoted.Expr[T] =
val tree = PickledQuotes.unpickleTerm(pickled, PickledQuotes.TypeHole.V1(typeHole), PickledQuotes.ExprHole.V1(termHole))
new ExprImpl(tree, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Expr[T]]
new ExprImpl(tree).asInstanceOf[scala.quoted.Expr[T]]

def unpickleExprV2[T](pickled: String | List[String], types: Seq[Type[?]], termHole: Null | ((Int, Seq[Type[?] | Expr[Any]], Quotes) => Expr[?])): scala.quoted.Expr[T] =
val tree = PickledQuotes.unpickleTerm(pickled, PickledQuotes.TypeHole.V2(types), PickledQuotes.ExprHole.V2(termHole))
new ExprImpl(tree, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Expr[T]]
new ExprImpl(tree).asInstanceOf[scala.quoted.Expr[T]]

def unpickleType[T <: AnyKind](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?]): scala.quoted.Type[T] =
val tree = PickledQuotes.unpickleTypeTree(pickled, PickledQuotes.TypeHole.V1(typeHole))
new TypeImpl(tree, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Type[T]]
new TypeImpl(tree).asInstanceOf[scala.quoted.Type[T]]

def unpickleTypeV2[T <: AnyKind](pickled: String | List[String], types: Seq[Type[?]]): scala.quoted.Type[T] =
val tree = PickledQuotes.unpickleTypeTree(pickled, PickledQuotes.TypeHole.V2(types))
new TypeImpl(tree, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Type[T]]
new TypeImpl(tree).asInstanceOf[scala.quoted.Type[T]]

object ExprMatch extends ExprMatchModule:
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
Expand Down
9 changes: 6 additions & 3 deletions compiler/src/scala/quoted/runtime/impl/TypeImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package scala.quoted
package runtime.impl

import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context

/** Quoted type (or kind) `T` backed by a tree */
final class TypeImpl(val typeTree: tpd.Tree, val scope: Scope) extends Type[?] {
final class TypeImpl(val typeTree: tpd.Tree)(using val ctx: Context) extends Type[?]:

def scope: Scope = SpliceScope.getCurrent

override def equals(that: Any): Boolean = that match {
case that: TypeImpl => typeTree ==
// TastyTreeExpr are wrappers around trees, therefore they are equals if their trees are equal.
Expand All @@ -15,5 +19,4 @@ final class TypeImpl(val typeTree: tpd.Tree, val scope: Scope) extends Type[?] {

override def hashCode(): Int = typeTree.hashCode()

override def toString: String = "Type.of[...]"
}
override def toString: String = QuotesImpl.showDecompiledTree(typeTree)
10 changes: 5 additions & 5 deletions tests/pos-with-compiler-cc/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -196,18 +196,18 @@ object PickledQuotes {
}

def reifyTypeHoleArgs(args: List[Tree])(using Context): List[scala.quoted.Type[?]] =
args.map(arg => new TypeImpl(arg, SpliceScope.getCurrent))
args.map(arg => new TypeImpl(arg)(using ctx.detach))

def reifyExprHoleV1Args(args: List[Tree])(using Context): List[ExprHole.ArgV1] =
args.map { arg =>
if arg.isTerm then (q: Quotes) ?=> new ExprImpl(arg, SpliceScope.getCurrent)
else new TypeImpl(arg, SpliceScope.getCurrent)
if arg.isTerm then (q: Quotes) ?=> new ExprImpl(arg)(using ctx.detach)
else new TypeImpl(arg)(using ctx.detach)
}

def reifyExprHoleV2Args(args: List[Tree])(using Context): List[ExprHole.ArgV2] =
args.map { arg =>
if arg.isTerm then new ExprImpl(arg, SpliceScope.getCurrent)
else new TypeImpl(arg, SpliceScope.getCurrent)
if arg.isTerm then new ExprImpl(arg)(using ctx.detach)
else new TypeImpl(arg)(using ctx.detach)
}

// TASTY picklingtests/pos/quoteTest.scala
Expand Down
4 changes: 2 additions & 2 deletions tests/pos-with-compiler-cc/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,11 @@ object Splicer {
case Inlined(EmptyTree, _, quoted) => quoted
case _ => quoted
}
new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(quoted1, ctx.owner)).withSpan(quoted1.span), SpliceScope.getCurrent)
new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(quoted1, ctx.owner)).withSpan(quoted1.span))(using ctx.detach)

// Interpret level -1 `Type.of[T]`
case Apply(TypeApply(fn, quoted :: Nil), _) if fn.symbol == defn.QuotedTypeModule_of =>
new TypeImpl(QuoteUtils.changeOwnerOfTree(quoted, ctx.owner), SpliceScope.getCurrent)
new TypeImpl(QuoteUtils.changeOwnerOfTree(quoted, ctx.owner))(using ctx.detach)

case _ =>
super.interpretTree(tree)
Expand Down
4 changes: 4 additions & 0 deletions tests/run-macros/Expr-toString.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
1
"abc"
scala.Predef.println("abc")
while (true) ()
6 changes: 6 additions & 0 deletions tests/run-macros/Expr-toString/Macros_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import scala.quoted.*

inline def showToString(inline x: Any): String = ${ macroImpl('x) }

private def macroImpl(x: Expr[Any])(using Quotes): Expr[String] =
Expr(x.toString)
5 changes: 5 additions & 0 deletions tests/run-macros/Expr-toString/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@main def Test() =
println(showToString(1))
println(showToString("abc"))
println(showToString(println("abc")))
println(showToString { while true do () } )
7 changes: 7 additions & 0 deletions tests/run-macros/Type-toString.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
1
"abc"
scala.Int
scala.collection.immutable.List[scala.Int]
java.lang.Object {
def foo: scala.Int
}
6 changes: 6 additions & 0 deletions tests/run-macros/Type-toString/Macros_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import scala.quoted.*

inline def showToString[T]: String = ${ macroImpl[T] }

private def macroImpl[T: Type](using Quotes): Expr[String] =
Expr(Type.of[T].toString)
6 changes: 6 additions & 0 deletions tests/run-macros/Type-toString/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@main def Test() =
println(showToString[1])
println(showToString["abc"])
println(showToString[Int])
println(showToString[List[Int]])
println(showToString[Object { def foo: Int }])