Skip to content

Commit 7a1e933

Browse files
committed
Refine handling of inline parameters of macros
These are at runtime trees with constant types. We can extract the constant from the tree, so they can also be used in a splicing context.
1 parent 6cf9c66 commit 7a1e933

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ import SymUtils._
1515
import NameKinds.OuterSelectName
1616
import scala.collection.mutable
1717

18-
// TODO
19-
// adapt to Expr/Type when passing arguments to splices
20-
2118
/** Translates quoted terms and types to `unpickle` method calls.
2219
* Checks that the phase consistency principle (PCP) holds.
2320
*/
@@ -173,6 +170,19 @@ class ReifyQuotes extends MacroTransform {
173170
case _ =>
174171
}
175172

173+
/** Does the level of `sym` match the current level?
174+
* An exception is made for inline vals in macros. These are also OK if their level
175+
* is one higher than the current level, because on execution such values
176+
* are constant expression trees and we can pull out the constant from the tree.
177+
*/
178+
def levelOK(sym: Symbol)(implicit ctx: Context): Boolean = levelOf.get(sym) match {
179+
case Some(l) =>
180+
l == level ||
181+
sym.is(Inline) && sym.owner.is(Macro) && sym.info.isValueType && l - 1 == level
182+
case None =>
183+
true
184+
}
185+
176186
/** Issue a "splice outside quote" error unless we ar in the body of an inline method */
177187
def spliceOutsideQuotes(pos: Position)(implicit ctx: Context) =
178188
ctx.error(i"splice outside quotes", pos)
@@ -188,7 +198,7 @@ class ReifyQuotes extends MacroTransform {
188198
else i"${sym.name}.this"
189199
if (!isThis && sym.maybeOwner.isType)
190200
check(sym.owner, sym.owner.thisType, pos)
191-
else if (sym.exists && !sym.isStaticOwner && levelOf.getOrElse(sym, level) != level)
201+
else if (sym.exists && !sym.isStaticOwner && !levelOK(sym))
192202
tp match {
193203
case tp: TypeRef =>
194204
importedTypes += tp
@@ -329,7 +339,8 @@ class ReifyQuotes extends MacroTransform {
329339
cpy.Select(expansion)(cpy.Inlined(tree)(call, bindings, body), name)
330340
case _: Import =>
331341
tree
332-
case tree: DefDef if tree.symbol.is(Macro) =>
342+
case tree: DefDef if tree.symbol.is(Macro) && level == 0 =>
343+
markDef(tree)
333344
val tree1 = nested(isQuote = true).transform(tree)
334345
// check macro code as it if appeared in a quoted context
335346
cpy.DefDef(tree)(rhs = EmptyTree)

tests/neg/inlinevals.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ object Test {
1717

1818
inline val M = X // error: rhs must be constant expression
1919

20+
inline val xs = List(1, 2, 3) // error: must be a constant expression
21+
22+
def f(inline xs: List[Int]) = xs
23+
24+
f(List(1, 2, 3)) // error: must be a constant expression
25+
2026
def byname(inline f: => String): Int = ??? // ok
2127

2228
byname("hello" ++ " world")

tests/pos/quoted.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ class Test {
1010
def assertImpl(expr: Expr[Boolean]) =
1111
'{ if !(~expr) then throw new AssertionError(s"failed assertion: ${~expr}") }
1212

13+
inline def power(inline n: Int, x: Double) = ~powerCode(n, '(x))
14+
15+
def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
16+
if (n == 0) '(1.0)
17+
else if (n == 1) x
18+
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
19+
else '{ ~x * ~powerCode(n - 1, x) }
1320
}
1421

1522
val program = '{
@@ -19,6 +26,12 @@ class Test {
1926
assert(x != 0)
2027

2128
~assertImpl('(x != 0))
29+
30+
val y = math.sqrt(2.0)
31+
32+
power(3, y)
33+
34+
~powerCode(3, '{math.sqrt(2.0)})
2235
}
2336

2437
program.run

0 commit comments

Comments
 (0)