Skip to content

Commit 4ad4373

Browse files
committed
Implement compiletime.code with a macro
Now, the implemetation is simpler with macros.
1 parent 37bc11d commit 4ad4373

File tree

4 files changed

+19
-49
lines changed

4 files changed

+19
-49
lines changed

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -705,41 +705,6 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
705705
case _ =>
706706
}
707707

708-
def issueCode()(using Context): Literal = {
709-
def decompose(arg: Tree): String = arg match {
710-
case Typed(arg, _) => decompose(arg)
711-
case SeqLiteral(elems, _) => elems.map(decompose).mkString(", ")
712-
case Block(Nil, expr) => decompose(expr)
713-
case Inlined(_, Nil, expr) => decompose(expr)
714-
case arg =>
715-
arg.tpe.widenTermRefExpr match {
716-
case ConstantType(Constant(c)) => c.toString
717-
case _ => arg.show
718-
}
719-
}
720-
721-
def malformedString(): String = {
722-
ctx.error("Malformed part `code` string interpolator", call.sourcePos)
723-
""
724-
}
725-
726-
callValueArgss match {
727-
case List(List(Apply(_,List(Typed(SeqLiteral(Literal(headConst) :: parts,_),_)))), List(Typed(SeqLiteral(interpolatedParts,_),_)))
728-
if parts.size == interpolatedParts.size =>
729-
val constantParts = parts.map {
730-
case Literal(const) => const.stringValue
731-
case _ => malformedString()
732-
}
733-
val decomposedInterpolations = interpolatedParts.map(decompose)
734-
val constantString = decomposedInterpolations.zip(constantParts)
735-
.foldLeft(headConst.stringValue) { case (acc, (p1, p2)) => acc + p1 + p2 }
736-
737-
Literal(Constant(constantString)).withSpan(call.span)
738-
case _ =>
739-
Literal(Constant(malformedString()))
740-
}
741-
}
742-
743708
trace(i"inlining $call", inlining, show = true) {
744709

745710
// The normalized bindings collected in `bindingsBuf`
@@ -763,12 +728,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
763728

764729
if (inlinedMethod == defn.Compiletime_error) issueError()
765730

766-
if (inlinedMethod == defn.Compiletime_code)
767-
issueCode()(using ctx.fresh.setSetting(ctx.settings.color, "never"))
768-
else
769-
// Take care that only argument bindings go into `bindings`, since positions are
770-
// different for bindings from arguments and bindings from body.
771-
tpd.Inlined(call, finalBindings, finalExpansion)
731+
// Take care that only argument bindings go into `bindings`, since positions are
732+
// different for bindings from arguments and bindings from body.
733+
tpd.Inlined(call, finalBindings, finalExpansion)
772734
}
773735
}
774736

library/src/scala/compiletime/package.scala

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package scala
22

3+
import scala.quoted._
4+
35
package object compiletime {
46

57
erased def erasedValue[T]: T = ???
@@ -17,7 +19,7 @@ package object compiletime {
1719
*/
1820
inline def error(inline msg: String): Nothing = ???
1921

20-
/** Returns the string representation of interpolated values:
22+
/** Returns the string representation of interpolated elaborated code:
2123
*
2224
* ```scala
2325
* inline def logged(p1: => Any) = {
@@ -27,13 +29,19 @@ package object compiletime {
2729
* }
2830
* logged(identity("foo"))
2931
* // above is equivalent to:
30-
* // ("code: identity("foo")", identity("foo"))
32+
* // ("code: scala.Predef.identity("foo")", identity("foo"))
3133
* ```
3234
*
3335
* @note only by-name arguments will be displayed as "code".
3436
* Other values may display unintutively.
3537
*/
36-
inline def (self: => StringContext) code (args: => Any*): String = ???
38+
transparent inline def (inline self: StringContext) code (inline args: Any*): String = ${ codeExpr('self, 'args) }
39+
private def codeExpr(using qctx: QuoteContext)(sc: Expr[StringContext], args: Expr[Seq[Any]]): Expr[String] =
40+
(sc, args) match
41+
case ('{ StringContext(${Varargs(Consts(parts))}: _*) }, Varargs(args2)) =>
42+
Expr(StringContext(parts: _*).s(args2.map(_.show): _*))
43+
case _ =>
44+
qctx.throwError("compiletime.code must be used as a string interpolator code\"...\"")
3745

3846
inline def constValueOpt[T]: Option[T] = ???
3947

tests/neg/i6622f.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
-- Error: tests/neg/i6622f.scala:6:8 -----------------------------------------------------------------------------------
22
6 | fail(println("foo")) // error
33
| ^^^^^^^^^^^^^^^^^^^^
4-
| failed: println("foo") ...
4+
| failed: scala.Predef.println("foo") ...

tests/run/i6622.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import scala.compiletime._
33
object Test {
44

55
def main(args: Array[String]): Unit = {
6-
assert(code"abc ${println(34)} ..." == "abc println(34) ...")
7-
assert(code"abc ${println(34)}" == "abc println(34)")
8-
assert(code"${println(34)} ..." == "println(34) ...")
9-
assert(code"${println(34)}" == "println(34)")
6+
assert(code"abc ${println(34)} ..." == "abc scala.Predef.println(34) ...")
7+
assert(code"abc ${println(34)}" == "abc scala.Predef.println(34)")
8+
assert(code"${println(34)} ..." == "scala.Predef.println(34) ...")
9+
assert(code"${println(34)}" == "scala.Predef.println(34)")
1010
assert(code"..." == "...")
1111
assert(testConstant(code"") == "")
1212
}

0 commit comments

Comments
 (0)