Skip to content

Add customizable names for definitions in quotes #7346

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

Merged
merged 3 commits into from
Oct 8, 2019
Merged
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
24 changes: 24 additions & 0 deletions library/src/scala/internal/quoted/showName.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package scala.internal.quoted

/** Annotation used inside a quote to give a custom name to a definition.
* The `name` argument must be a literal String.
*
* Usage:
* ```scala
* def let(name: String)(value: Expr[Int])(in: Expr[Int] => Expr[Int]): Expr[Int] = '{
* @showName(${Expr(name)})
* val x = $value
* ${ in('x) }
* }
* ```
* then using it in
* ```scala
* let("myVal")('{4})(x => '{ $x + 1}).show
* ```
* will retuns the code
* ```scala
* val myVal = 4
* myVal + 1
* ```
*/
class showName(name: String) extends scala.annotation.Annotation
36 changes: 26 additions & 10 deletions library/src/scala/tasty/reflect/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,8 @@ trait Printers
if (vdef.symbol.flags.is(Flags.Mutable)) this += highlightKeyword("var ")
else this += highlightKeyword("val ")

this += highlightValDef(name) += ": "
val name1 = splicedName(vdef.symbol).getOrElse(name)
this += highlightValDef(name1) += ": "
printTypeTree(tpt)
rhs match {
case Some(tree) =>
Expand Down Expand Up @@ -714,7 +715,8 @@ trait Printers

printProtectedOrPrivate(ddef)

this += highlightKeyword("def ") += highlightValDef((if (isConstructor) "this" else name))
val name1: String = if (isConstructor) "this" else splicedName(ddef.symbol).getOrElse(name)
this += highlightKeyword("def ") += highlightValDef(name1)
printTargsDefs(targs.zip(targs))
val it = argss.iterator
while (it.hasNext)
Expand All @@ -734,8 +736,11 @@ trait Printers
case Ident("_") =>
this += "_"

case IsTerm(tree @ Ident(_)) =>
printType(tree.tpe)
case IsIdent(tree) =>
splicedName(tree.symbol) match {
case Some(name) => this += name
case _ => printType(tree.tpe)
}

case Select(qual, name) =>
printQualTree(qual)
Expand Down Expand Up @@ -1637,12 +1642,15 @@ trait Printers

def printAnnotation(annot: Term)(given elideThis: Option[Symbol]): Buffer = {
val Annotation(ref, args) = annot
this += "@"
printTypeTree(ref)
if (args.isEmpty)
this
else
inParens(printTrees(args, ", "))
if (annot.symbol.owner.fullName == "scala.internal.quoted.showName") this
else {
this += "@"
printTypeTree(ref)
if (args.isEmpty)
this
else
inParens(printTrees(args, ", "))
}
}

def printDefAnnotations(definition: Definition)(given elideThis: Option[Symbol]): Buffer = {
Expand Down Expand Up @@ -1809,6 +1817,14 @@ trait Printers
private def escapedString(str: String): String = str flatMap escapedChar
}

private def splicedName(sym: Symbol)(given ctx: Context): Option[String] = {
sym.annots.find(_.symbol.owner.fullName == "scala.internal.quoted.showName").flatMap {
case Apply(_, Literal(Constant(c: String)) :: Nil) => Some(c)
case Apply(_, Inlined(_, _, Literal(Constant(c: String))) :: Nil) => Some(c)
case annot => None
}
}

private object SpecialOp {
def unapply(arg: Tree)(given ctx: Context): Option[(String, List[Term])] = arg match {
case IsTerm(arg @ Apply(fn, args)) =>
Expand Down
13 changes: 13 additions & 0 deletions tests/run-staging/quoted-show-name.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
((x1: scala.Double) => x1.*({
val x2: scala.Double = x1.*(x1)
val x4: scala.Double = x2.*(x2)
x4.*({
val x8: scala.Double = x4.*(x4)
x8.*({
val x16: scala.Double = x8.*(x8)
val x32: scala.Double = x16.*(x16)
val x64: scala.Double = x32.*(x32)
x64
})
})
}))
21 changes: 21 additions & 0 deletions tests/run-staging/quoted-show-name.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import scala.quoted._
import scala.internal.quoted.showName
import scala.quoted.staging._
import scala.reflect.ClassTag

object Test {
given Toolbox = Toolbox.make(getClass.getClassLoader)
def main(args: Array[String]): Unit = withQuoteContext {
println(powerCode(77).show)
}

def powerCode(n: Long)(given QuoteContext): Expr[Double => Double] =
'{ x1 => ${powerCode(n, 2, 'x1)} }

def powerCode(n: Long, idx: Int, x: Expr[Double])(given QuoteContext): Expr[Double] =
if (n == 0) '{1.0}
else if (n == 1) x
else if (n % 2 == 0) '{ @showName(${Expr("x" + idx)}) val y = $x * $x; ${powerCode(n / 2, idx * 2, '{y})} }
else '{ $x * ${powerCode(n - 1, idx, x)} }

}