diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 16956ce352f3..1098d8822f05 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -224,7 +224,7 @@ class Definitions { @tu lazy val ScalaXmlPackageClass: Symbol = getPackageClassIfDefined("scala.xml") @tu lazy val CompiletimePackageObject: Symbol = requiredModule("scala.compiletime.package") - @tu lazy val Compiletime_code: Symbol = CompiletimePackageObject.requiredMethod("code") + @tu lazy val Compiletime_codeOf: Symbol = CompiletimePackageObject.requiredMethod("codeOf") @tu lazy val Compiletime_erasedValue : Symbol = CompiletimePackageObject.requiredMethod("erasedValue") @tu lazy val Compiletime_error : Symbol = CompiletimePackageObject.requiredMethod(nme.error) @tu lazy val Compiletime_requireConst: Symbol = CompiletimePackageObject.requiredMethod("requireConst") diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 21dfb55539bf..dd545d6d9df8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -333,31 +333,9 @@ object Inliner { val errors = compileForErrors(tree, false) packErrors(errors) - def code(strCtx: Tree, argsTree: Tree, pos: SrcPos)(using Context): Tree = - object Consts: - def unapply(trees: List[Tree]): Option[List[String]] = - trees match - case Nil => Some(Nil) - case Literal(Constant(part: String)) :: Consts(rest) => Some(part :: rest) - case _ => None - strCtx match - case Apply(stringContextApply, List(Typed(SeqLiteral(Consts(parts), _), _))) - if stringContextApply.symbol == defn.StringContextModule_apply => - argsTree match - case Typed(SeqLiteral(args, _), _) => - if parts.size == args.size + 1 then - val argStrs = args.map(_.show) - val showed = StringContext(parts: _*).s(argStrs: _*) - Literal(Constant(showed)).withSpan(pos.span) - else - report.error("Wrong number of arguments for StringContext.s", strCtx.srcPos) - ref(defn.Predef_undefined) - case _ => - report.error("Exprected explicit arguments to code", strCtx.srcPos) - ref(defn.Predef_undefined) - case _ => - report.error("Exprected StringContext.apply with explicit `parts` arguments", strCtx.srcPos) - ref(defn.Predef_undefined) + /** Expand call to scala.compiletime.codeOf */ + def codeOf(arg: Tree, pos: SrcPos)(using Context): Tree = + Literal(Constant(arg.show)).withSpan(pos.span) } } @@ -642,15 +620,16 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { /** The Inlined node representing the inlined call */ def inlined(sourcePos: SrcPos): Tree = { - // Special handling of `requireConst` + // Special handling of `requireConst` and `codeOf` callValueArgss match - case (arg :: Nil) :: Nil if inlinedMethod == defn.Compiletime_requireConst => - arg match - case ConstantValue(_) | Inlined(_, Nil, Typed(ConstantValue(_), _)) => // ok - case _ => report.error(em"expected a constant value but found: $arg", arg.srcPos) - return Literal(Constant(())).withSpan(sourcePos.span) - case (strCtx :: Nil) :: (args :: Nil) :: Nil if inlinedMethod == defn.Compiletime_code => - return Intrinsics.code(strCtx, args, call.srcPos) + case (arg :: Nil) :: Nil => + if inlinedMethod == defn.Compiletime_requireConst then + arg match + case ConstantValue(_) | Inlined(_, Nil, Typed(ConstantValue(_), _)) => // ok + case _ => report.error(em"expected a constant value but found: $arg", arg.srcPos) + return Literal(Constant(())).withSpan(sourcePos.span) + else if inlinedMethod == defn.Compiletime_codeOf then + return Intrinsics.codeOf(arg, call.srcPos) case _ => // Special handling of `constValue[T]` and `constValueOpt[T]` diff --git a/library/src/scala/compiletime/package.scala b/library/src/scala/compiletime/package.scala index 83a5a2232dd9..5ca5e4892bf0 100644 --- a/library/src/scala/compiletime/package.scala +++ b/library/src/scala/compiletime/package.scala @@ -26,40 +26,31 @@ package object compiletime { * ``` * or * ```scala - * error(code"My error of this code: ${println("foo")}") - * ``` - * or - * ```scala * inline def errorOnThisCode(inline x: Any) = - * error(code"My error of this code: $x") + * error("My error of this code: " + codeOf(x)) * ``` */ inline def error(inline msg: String): Nothing = ??? - extension (inline self: StringContext): - /** Returns the string representation of interpolated elaborated code: - * - * ```scala - * inline def logged(inline p1: Any) = { - * val c = code"code: $p1" - * val res = p1 - * (c, p1) - * } - * logged(identity("foo")) - * // above is equivalent to: - * // ("code: scala.Predef.identity("foo")", identity("foo")) - * ``` - * - * The formatting of the code is not stable across version of the compiler. - * - * @note only `inline` arguments will be displayed as "code". - * Other values may display unintutively. - */ - transparent inline def code (inline args: Any*): String = - // implemented in dotty.tools.dotc.typer.Inliner.Intrinsics - error("Compiler bug: `code` was not evaluated by the compiler") - - end extension + /** Returns the string representation of argument code: + * + * ```scala + * inline def logged(inline p1: Any) = + * ("code: " + codeOf(p1), p1) + * + * logged(identity("foo")) + * // above is equivalent to: + * // ("code: scala.Predef.identity("foo")", identity("foo")) + * ``` + * + * The formatting of the code is not stable across version of the compiler. + * + * @note only `inline` arguments will be displayed as "code". + * Other values may display unintutively. + */ + transparent inline def codeOf(arg: Any): String = + // implemented in dotty.tools.dotc.typer.Inliner.Intrinsics + error("Compiler bug: `codeOf` was not evaluated by the compiler") /** Checks at compiletime that the provided values is a constant after * inlining and constant folding. diff --git a/tests/neg-macros/i6622f.scala b/tests/neg-macros/i6622f.scala index 72dd8308e071..e5d323815e79 100644 --- a/tests/neg-macros/i6622f.scala +++ b/tests/neg-macros/i6622f.scala @@ -6,6 +6,6 @@ object Test { fail(println("foo")) // error } - inline def fail(inline p1: Any) = error(code"failed: $p1 ...") + inline def fail(inline p1: Any) = error("failed: " + codeOf(p1) + " ...") } diff --git a/tests/run-macros/beta-reduce-inline-result/Test_2.scala b/tests/run-macros/beta-reduce-inline-result/Test_2.scala index bb781c2da284..247dffe61c79 100644 --- a/tests/run-macros/beta-reduce-inline-result/Test_2.scala +++ b/tests/run-macros/beta-reduce-inline-result/Test_2.scala @@ -45,9 +45,9 @@ object Test { { (i: Int) => i + 1 } : V def main(argv : Array[String]) : Unit = { - println(code"compile-time: ${Macros.betaReduce(dummy1)(3)}") + println(s"compile-time: ${codeOf(Macros.betaReduce(dummy1)(3))}") println(s"run-time: ${Macros.betaReduce(dummy1)(3)}") - println(code"compile-time: ${Macros.betaReduce(dummy2)(1)}") + println(s"compile-time: ${codeOf(Macros.betaReduce(dummy2)(1))}") // paramrefs have to be properly substituted in this case println(s"run-time: ${Macros.betaReduce(dummy2)(1)}") diff --git a/tests/run-macros/i6622.check b/tests/run-macros/i6622.check index 951a493b2f45..0e401ebf1362 100644 --- a/tests/run-macros/i6622.check +++ b/tests/run-macros/i6622.check @@ -1,6 +1 @@ abc println(34) ... -abc println(34) -println(34) ... -println(34) -... - diff --git a/tests/run-macros/i6622.scala b/tests/run-macros/i6622.scala index 566877fcc8ca..e883a212bf2f 100644 --- a/tests/run-macros/i6622.scala +++ b/tests/run-macros/i6622.scala @@ -3,13 +3,9 @@ import scala.compiletime._ object Test { def main(args: Array[String]): Unit = { - println(code"abc ${println(34)} ...") - println(code"abc ${println(34)}") - println(code"${println(34)} ...") - println(code"${println(34)}") - println(code"...") - println(testConstant(code"")) + println(s"abc ${codeOf(println(34))} ...") } + inline def testConstant(inline msg: String): String = msg } diff --git a/tests/run-macros/i8306.scala b/tests/run-macros/i8306.scala index 678fc390defd..dbb9d6870f08 100644 --- a/tests/run-macros/i8306.scala +++ b/tests/run-macros/i8306.scala @@ -56,38 +56,38 @@ object Test extends Test8 { } def main(argv: Array[String]): Unit = { - println(code"compile-time: ${test1}") - println(s"run-time: ${test1}") + println(s"compile-time: ${codeOf(test1)}") + println(s"run-time: ${codeOf(test1)}") - println(code"compile-time: ${test2}") - println(s"run-time: ${test2}") + println(s"compile-time: ${codeOf(test2)}") + println(s"run-time: ${codeOf(test2)}") - println(code"compile-time: ${test3}") - println(s"run-time: ${test3}") + println(s"compile-time: ${codeOf(test3)}") + println(s"run-time: ${codeOf(test3)}") - println(code"compile-time: ${test4}") - println(s"run-time: ${test4}") + println(s"compile-time: ${codeOf(test4)}") + println(s"run-time: ${codeOf(test4)}") // this is the only test that should not be possible to fully inline, // because it references a non-inline value - println(code"compile-time: ${test5}") - println(s"run-time: ${test5}") + println(s"compile-time: ${codeOf(test5)}") + println(s"run-time: ${codeOf(test5)}") - println(code"compile-time: ${test6}") - println(s"run-time: ${test6}") + println(s"compile-time: ${codeOf(test6)}") + println(s"run-time: ${codeOf(test6)}") - println(code"compile-time: ${test7}") - println(s"run-time: ${test7}") + println(s"compile-time: ${codeOf(test7)}") + println(s"run-time: ${codeOf(test7)}") - println(code"compile-time: ${test8}") - println(s"run-time: ${test8}") + println(s"compile-time: ${codeOf(test8)}") + println(s"run-time: ${codeOf(test8)}") - println(code"compile-time: ${test9}") - println(s"run-time: ${test9}") + println(s"compile-time: ${codeOf(test9)}") + println(s"run-time: ${codeOf(test9)}") // with type parameter - println(code"compile-time: ${test10}") - println(s"run-time: ${test10}") + println(s"compile-time: ${codeOf(test10)}") + println(s"run-time: ${codeOf(test10)}") } }