Skip to content

Commit 8b1a65a

Browse files
committed
Fix #3912: account for units and blocks in inline and macros
1 parent 3365ed3 commit 8b1a65a

File tree

8 files changed

+72
-5
lines changed

8 files changed

+72
-5
lines changed

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,19 @@ class ReifyQuotes extends MacroTransformWithImplicits {
321321
val last = enteredSyms
322322
stats.foreach(markDef)
323323
mapOverTree(last)
324-
case Inlined(call, bindings, expansion @ Select(body, name)) if expansion.symbol.isSplice =>
324+
case Inlined(call, bindings, InlineSplice(expansion @ Select(body, name))) =>
325+
325326
// To maintain phase consistency, convert inlined expressions of the form
326327
// `{ bindings; ~expansion }` to `~{ bindings; expansion }`
327-
if (level == 0) transform(Splicer.splice(cpy.Inlined(tree)(call, bindings, body)))
328-
else transform(cpy.Select(expansion)(cpy.Inlined(tree)(call, bindings, body), name))
328+
// `{ bindings; { ~expansion } }` to `~{ bindings; expansion }`
329+
// `{ bindings; { ~expansion; () } }` to `~{ bindings; expansion; () }`
330+
val inlinedWithoutSplice = cpy.Inlined(tree)(call, bindings, body)
331+
val t =
332+
if (level == 0) transform(Splicer.splice(inlinedWithoutSplice))
333+
else transform(cpy.Select(expansion)(inlinedWithoutSplice, name))
334+
335+
if (tree.tpe =:= defn.UnitType) Block(t :: Nil, Literal(Constant(())))
336+
else t
329337
case _: Import =>
330338
tree
331339
case tree: DefDef if tree.symbol.is(Macro) && level == 0 =>
@@ -338,5 +346,20 @@ class ReifyQuotes extends MacroTransformWithImplicits {
338346
checkLevel(mapOverTree(enteredSyms))
339347
}
340348
}
349+
350+
/** InlineSplice is used to detect cases where the expansion
351+
* consists of a (possibly multiple & nested) block or a sole expression.
352+
*/
353+
object InlineSplice {
354+
def unapply(tree: Tree)(implicit ctx: Context): Option[Select] = {
355+
tree match {
356+
case expansion: Select if expansion.symbol.isSplice =>
357+
Some(expansion)
358+
case Block(List(stat), Literal(Constant(()))) => unapply(stat)
359+
case Block(Nil, expr) => unapply(expr)
360+
case _ => None
361+
}
362+
}
363+
}
341364
}
342365
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import dotty.tools.dotc.core.Contexts._
66
import dotty.tools.dotc.core.quoted._
77
import dotty.tools.dotc.interpreter._
88

9-
/** Utility class to slice quoted expressions */
9+
/** Utility class to splice quoted expressions */
1010
object Splicer {
1111
import tpd._
1212

1313
/** Splice the Tree for a Quoted expression. `~'(xyz)` becomes `xyz`
1414
* and for `~xyz` the tree of `xyz` is interpreted for which the
15-
* resulting expression is return as a `Tree`
15+
* resulting expression is returned as a `Tree`
1616
*/
1717
def splice(tree: Tree)(implicit ctx: Context): Tree = tree match {
1818
case Quoted(quotedTree) => quotedTree

tests/pos/i3912-1/i3912_1.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
inline def foo(): Int = { ~impl() }
5+
6+
def impl(): Expr[Int] = '(1)
7+
}

tests/pos/i3912-1/i3912_2.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
class Test {
5+
val a: Unit = foo()
6+
7+
}

tests/pos/i3912-2/i3912_1.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
inline def foo2(): Unit = ~impl()
5+
6+
def impl(): Expr[Int] = '(1)
7+
}

tests/pos/i3912-2/i3912_2.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
class Test {
5+
val a2: Unit = foo2()
6+
}

tests/pos/i3912-3/i3912_1.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
inline def foo3(): Int = {
5+
{
6+
~impl()
7+
}
8+
}
9+
10+
def impl(): Expr[Int] = '(1)
11+
}

tests/pos/i3912-3/i3912_2.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
class Test {
5+
val a3: Unit = foo3()
6+
}

0 commit comments

Comments
 (0)