Skip to content

Commit 6b9796c

Browse files
Merge pull request #10296 from dotty-staging/intrisify-scala.compiletime.code
Intrinify scala.compiletime.code
2 parents 3f6efd9 + ee00a1d commit 6b9796c

File tree

9 files changed

+71
-36
lines changed

9 files changed

+71
-36
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ class Definitions {
224224
@tu lazy val ScalaXmlPackageClass: Symbol = getPackageClassIfDefined("scala.xml")
225225

226226
@tu lazy val CompiletimePackageObject: Symbol = requiredModule("scala.compiletime.package")
227+
@tu lazy val Compiletime_code: Symbol = CompiletimePackageObject.requiredMethod("code")
227228
@tu lazy val Compiletime_erasedValue : Symbol = CompiletimePackageObject.requiredMethod("erasedValue")
228229
@tu lazy val Compiletime_error : Symbol = CompiletimePackageObject.requiredMethod(nme.error)
229230
@tu lazy val Compiletime_requireConst: Symbol = CompiletimePackageObject.requiredMethod("requireConst")

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,32 @@ object Inliner {
332332
def typeCheckErrors(tree: Tree)(using Context): Tree =
333333
val errors = compileForErrors(tree, false)
334334
packErrors(errors)
335+
336+
def code(strCtx: Tree, argsTree: Tree, pos: SrcPos)(using Context): Tree =
337+
object Consts:
338+
def unapply(trees: List[Tree]): Option[List[String]] =
339+
trees match
340+
case Nil => Some(Nil)
341+
case Literal(Constant(part: String)) :: Consts(rest) => Some(part :: rest)
342+
case _ => None
343+
strCtx match
344+
case Apply(stringContextApply, List(Typed(SeqLiteral(Consts(parts), _), _)))
345+
if stringContextApply.symbol == defn.StringContextModule_apply =>
346+
argsTree match
347+
case Typed(SeqLiteral(args, _), _) =>
348+
if parts.size == args.size + 1 then
349+
val argStrs = args.map(_.show)
350+
val showed = StringContext(parts: _*).s(argStrs: _*)
351+
Literal(Constant(showed)).withSpan(pos.span)
352+
else
353+
report.error("Wrong number of arguments for StringContext.s", strCtx.srcPos)
354+
ref(defn.Predef_undefined)
355+
case _ =>
356+
report.error("Exprected explicit arguments to code", strCtx.srcPos)
357+
ref(defn.Predef_undefined)
358+
case _ =>
359+
report.error("Exprected StringContext.apply with explicit `parts` arguments", strCtx.srcPos)
360+
ref(defn.Predef_undefined)
335361
}
336362
}
337363

@@ -622,6 +648,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
622648
arg match
623649
case ConstantValue(_) | Inlined(_, Nil, Typed(ConstantValue(_), _)) => // ok
624650
case _ => report.error(em"expected a constant value but found: $arg", arg.srcPos)
651+
return Literal(Constant(())).withSpan(sourcePos.span)
652+
case (strCtx :: Nil) :: (args :: Nil) :: Nil if inlinedMethod == defn.Compiletime_code =>
653+
return Intrinsics.code(strCtx, args, call.srcPos)
625654
case _ =>
626655

627656
// Special handling of `constValue[T]` and `constValueOpt[T]`

library/src-bootstrapped/dotty/internal/CompileTimeMacros.scala

Lines changed: 0 additions & 11 deletions
This file was deleted.

library/src-non-bootstrapped/dotty/internal/CompileTimeMacros.scala

Lines changed: 0 additions & 7 deletions
This file was deleted.

library/src/scala/compiletime/package.scala

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,19 @@ package object compiletime {
2828
* ```scala
2929
* error(code"My error of this code: ${println("foo")}")
3030
* ```
31+
* or
32+
* ```scala
33+
* inline def errorOnThisCode(inline x: Any) =
34+
* error(code"My error of this code: $x")
35+
* ```
3136
*/
3237
inline def error(inline msg: String): Nothing = ???
3338

3439
extension (inline self: StringContext):
3540
/** Returns the string representation of interpolated elaborated code:
3641
*
3742
* ```scala
38-
* inline def logged(p1: => Any) = {
43+
* inline def logged(inline p1: Any) = {
3944
* val c = code"code: $p1"
4045
* val res = p1
4146
* (c, p1)
@@ -45,11 +50,15 @@ package object compiletime {
4550
* // ("code: scala.Predef.identity("foo")", identity("foo"))
4651
* ```
4752
*
48-
* @note only by-name arguments will be displayed as "code".
53+
* The formatting of the code is not stable across version of the compiler.
54+
*
55+
* @note only `inline` arguments will be displayed as "code".
4956
* Other values may display unintutively.
5057
*/
5158
transparent inline def code (inline args: Any*): String =
52-
${ dotty.internal.CompileTimeMacros.codeExpr('self, 'args) }
59+
// implemented in dotty.tools.dotc.typer.Inliner.Intrinsics
60+
error("Compiler bug: `code` was not evaluated by the compiler")
61+
5362
end extension
5463

5564
/** Checks at compiletime that the provided values is a constant after
@@ -66,18 +75,24 @@ package object compiletime {
6675
* twice(m) // error: expected a constant value but found: m
6776
* ```
6877
*/
69-
inline def requireConst(inline x: Boolean | Byte | Short | Int | Long | Float | Double | Char | String): Unit = ()
78+
inline def requireConst(inline x: Boolean | Byte | Short | Int | Long | Float | Double | Char | String): Unit =
79+
// implemented in dotty.tools.dotc.typer.Inliner
80+
error("Compiler bug: `requireConst` was not evaluated by the compiler")
7081

7182
/** Same as `constValue` but returns a `None` if a constant value
7283
* cannot be constructed from the provided type. Otherwise returns
7384
* that value wrapped in `Some`.
7485
*/
75-
inline def constValueOpt[T]: Option[T] = ???
86+
inline def constValueOpt[T]: Option[T] =
87+
// implemented in dotty.tools.dotc.typer.Inliner
88+
error("Compiler bug: `constValueOpt` was not evaluated by the compiler")
7689

7790
/** Given a constant, singleton type `T`, convert it to a value
7891
* of the same singleton type. For example: `assert(constValue[1] == 1)`.
7992
*/
80-
inline def constValue[T]: T = ???
93+
inline def constValue[T]: T =
94+
// implemented in dotty.tools.dotc.typer.Inliner
95+
error("Compiler bug: `constValue` was not evaluated by the compiler")
8196

8297
/** Given a tuple type `(X1, ..., Xn)`, returns a tuple value
8398
* `(constValue[X1], ..., constValue[Xn])`.
@@ -104,8 +119,8 @@ package object compiletime {
104119
*
105120
* the returned value would be `2`.
106121
*/
107-
transparent inline def summonFrom[T](f: Nothing => T): T = ???
108-
122+
transparent inline def summonFrom[T](f: Nothing => T): T =
123+
error("Compiler bug: `summonFrom` was not evaluated by the compiler")
109124

110125
/** Summon a given value of type `T`. Usually, the argument is not passed explicitly.
111126
* The summoning is delayed until the call has been fully inlined.

library/src/scala/compiletime/testing/package.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ package object testing {
1111
* The code should be a sequence of expressions or statements that may appear in a block.
1212
*/
1313
inline def typeChecks(inline code: String): Boolean =
14-
error("`typeChecks` was not checked by the compiler")
14+
// implemented in package dotty.tools.dotc.typer.Inliner.Intrinsics
15+
error("Compiler bug: `typeChecks` was not checked by the compiler")
1516

1617
/** Whether the code type checks in the current context? If not,
1718
* returns a list of errors encountered on compilation.
@@ -27,5 +28,6 @@ package object testing {
2728
* The code should be a sequence of expressions or statements that may appear in a block.
2829
*/
2930
inline def typeCheckErrors(inline code: String): List[Error] =
30-
error("`typeCheckErrors` was not checked by the compiler")
31+
// implemented in package dotty.tools.dotc.typer.Inliner.Intrinsics
32+
error("Compiler bug: `typeCheckErrors` was not checked by the compiler")
3133
}

tests/run-macros/beta-reduce-inline-result.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
compile-time: (4: scala.Int)
1+
compile-time: 4:Int
22
run-time: 4
3-
compile-time: (1: scala.Int)
3+
compile-time: 1:Int
44
run-time: 1
55
run-time: 5
66
run-time: 7

tests/run-macros/i6622.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
abc println(34) ...
2+
abc println(34)
3+
println(34) ...
4+
println(34)
5+
...
6+

tests/run-macros/i6622.scala

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

55
def main(args: Array[String]): Unit = {
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)")
10-
assert(code"..." == "...")
11-
assert(testConstant(code"") == "")
6+
println(code"abc ${println(34)} ...")
7+
println(code"abc ${println(34)}")
8+
println(code"${println(34)} ...")
9+
println(code"${println(34)}")
10+
println(code"...")
11+
println(testConstant(code""))
1212
}
1313

1414
inline def testConstant(inline msg: String): String = msg

0 commit comments

Comments
 (0)