Skip to content

Commit c17dda0

Browse files
Merge pull request #5154 from dotty-staging/fix-#5144
Fix #5144: Avoid Expr of method type
2 parents 71b8334 + 757bb1e commit c17dda0

File tree

6 files changed

+83
-12
lines changed

6 files changed

+83
-12
lines changed

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import config.Config
2020

2121
object TreePickler {
2222

23-
case class Hole(idx: Int, args: List[tpd.Tree]) extends tpd.TermTree {
23+
case class Hole(idx: Int, args: List[tpd.Tree]) extends tpd.Tree {
2424
override def fallbackToText(printer: Printer): Text =
2525
s"[[$idx|" ~~ printer.toTextGlobal(args, ", ") ~~ "]]"
2626
}

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

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import util.Positions._
99
import tasty.TreePickler.Hole
1010
import SymUtils._
1111
import NameKinds._
12-
import dotty.tools.dotc.ast.tpd.Tree
12+
import dotty.tools.dotc.ast.tpd
1313
import typer.Implicits.SearchFailureType
1414

1515
import scala.collection.mutable
@@ -61,6 +61,7 @@ import dotty.tools.dotc.util.SourcePosition
6161
*/
6262
class ReifyQuotes extends MacroTransformWithImplicits {
6363
import ast.tpd._
64+
import ReifyQuotes._
6465

6566
/** Classloader used for loading macros */
6667
private[this] var myMacroClassLoader: java.lang.ClassLoader = _
@@ -90,7 +91,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
9091
if (ctx.compilationUnit.containsQuotesOrSplices) super.run
9192

9293
protected def newTransformer(implicit ctx: Context): Transformer =
93-
new Reifier(inQuote = false, null, 0, new LevelInfo, new mutable.ListBuffer, ctx)
94+
new Reifier(inQuote = false, null, 0, new LevelInfo, new Embedded, ctx)
9495

9596
private class LevelInfo {
9697
/** A map from locally defined symbols to the staging levels of their definitions */
@@ -123,13 +124,13 @@ class ReifyQuotes extends MacroTransformWithImplicits {
123124
* @param rctx the contex in the destination lifted lambda
124125
*/
125126
private class Reifier(inQuote: Boolean, val outer: Reifier, val level: Int, levels: LevelInfo,
126-
val embedded: mutable.ListBuffer[Tree], val rctx: Context) extends ImplicitsTransformer {
127+
val embedded: Embedded, val rctx: Context) extends ImplicitsTransformer {
127128
import levels._
128129
assert(level >= -1)
129130

130131
/** A nested reifier for a quote (if `isQuote = true`) or a splice (if not) */
131132
def nested(isQuote: Boolean)(implicit ctx: Context): Reifier = {
132-
val nestedEmbedded = if (level > 1 || (level == 1 && isQuote)) embedded else new mutable.ListBuffer[Tree]
133+
val nestedEmbedded = if (level > 1 || (level == 1 && isQuote)) embedded else new Embedded
133134
new Reifier(isQuote, this, if (isQuote) level + 1 else level - 1, levels, nestedEmbedded, ctx)
134135
}
135136

@@ -423,7 +424,8 @@ class ReifyQuotes extends MacroTransformWithImplicits {
423424
}
424425
else if (level == 1) {
425426
val (body1, quotes) = nested(isQuote = false).split(splice.qualifier)
426-
makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
427+
val tpe = outer.embedded.getHoleType(splice)
428+
makeHole(body1, quotes, tpe).withPos(splice.pos)
427429
}
428430
else if (enclosingInlineds.nonEmpty) { // level 0 in an inlined call
429431
val spliceCtx = ctx.outer // drop the last `inlineContext`
@@ -478,14 +480,18 @@ class ReifyQuotes extends MacroTransformWithImplicits {
478480
(captured: mutable.Map[Symbol, Tree]) => {
479481
(tree: Tree) => {
480482
def newCapture = {
481-
val tpw = tree.tpe.widen
483+
val tpw = tree.tpe.widen match {
484+
case tpw: MethodicType => tpw.toFunctionType()
485+
case tpw => tpw
486+
}
487+
assert(tpw.isInstanceOf[ValueType])
482488
val argTpe =
483489
if (tree.isType) defn.QuotedTypeType.appliedTo(tpw)
484490
else defn.QuotedExprType.appliedTo(tpw)
485491
val selectArg = arg.select(nme.apply).appliedTo(Literal(Constant(i))).asInstance(argTpe)
486492
val capturedArg = SyntheticValDef(UniqueName.fresh(tree.symbol.name.toTermName).toTermName, selectArg)
487493
i += 1
488-
embedded += tree
494+
embedded.addTree(tree, capturedArg.symbol)
489495
captured.put(tree.symbol, capturedArg)
490496
capturedArg
491497
}
@@ -526,15 +532,14 @@ class ReifyQuotes extends MacroTransformWithImplicits {
526532
*/
527533
private def split(tree: Tree)(implicit ctx: Context): (Tree, List[Tree]) = {
528534
val tree1 = if (inQuote) addTags(transform(tree)) else makeLambda(tree)
529-
(tree1, embedded.toList)
535+
(tree1, embedded.getTrees)
530536
}
531537

532538
/** Register `body` as an `embedded` quote or splice
533539
* and return a hole with `splices` as arguments and the given type `tpe`.
534540
*/
535541
private def makeHole(body: Tree, splices: List[Tree], tpe: Type)(implicit ctx: Context): Hole = {
536-
val idx = embedded.length
537-
embedded += body
542+
val idx = embedded.addTree(body, NoSymbol)
538543
Hole(idx, splices).withType(tpe).asInstanceOf[Hole]
539544
}
540545

@@ -624,10 +629,31 @@ class ReifyQuotes extends MacroTransformWithImplicits {
624629
object ReifyQuotes {
625630
val name = "reifyQuotes"
626631

627-
def toValue(tree: Tree): Option[Any] = tree match {
632+
def toValue(tree: tpd.Tree): Option[Any] = tree match {
628633
case Literal(Constant(c)) => Some(c)
629634
case Block(Nil, e) => toValue(e)
630635
case Inlined(_, Nil, e) => toValue(e)
631636
case _ => None
632637
}
638+
639+
class Embedded(trees: mutable.ListBuffer[tpd.Tree] = mutable.ListBuffer.empty, map: mutable.Map[Symbol, tpd.Tree] = mutable.Map.empty) {
640+
/** Adds the tree and returns it's index */
641+
def addTree(tree: tpd.Tree, liftedSym: Symbol): Int = {
642+
trees += tree
643+
if (liftedSym ne NoSymbol)
644+
map.put(liftedSym, tree)
645+
trees.length - 1
646+
}
647+
648+
/** Type used for the hole that will replace this splice */
649+
def getHoleType(splice: tpd.Select)(implicit ctx: Context): Type = {
650+
// For most expressions the splice.tpe but there are some types that are lost by lifting
651+
// that can be recoverd from the original tree. Currently the cases are:
652+
// * Method types: the splice represents a method reference
653+
map.get(splice.qualifier.symbol).map(_.tpe.widen).getOrElse(splice.tpe)
654+
}
655+
656+
/** Get the list of embedded trees */
657+
def getTrees: List[tpd.Tree] = trees.toList
658+
}
633659
}

tests/run-with-compiler/i5144.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
def f(x: scala.Int): scala.Int = ((x: scala.Int) => f(x)).apply(42)
3+
()
4+
}

tests/run-with-compiler/i5144.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make
5+
6+
def eval1(ff: Expr[Int => Int]): Expr[Int] = '((~ff)(42))
7+
8+
def peval1(): Expr[Unit] = '{
9+
def f(x: Int): Int = ~eval1('(f))
10+
}
11+
12+
def main(args: Array[String]): Unit = {
13+
val p = peval1()
14+
println(p.show)
15+
}
16+
17+
}

tests/run-with-compiler/i5144b.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
def f(x: scala.Int): scala.Int = {
3+
val x$1: scala.Int = 42
4+
f(x$1)
5+
}
6+
()
7+
}

tests/run-with-compiler/i5144b.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make
5+
6+
def eval1(ff: Expr[Int => Int]): Expr[Int] = ff('(42))
7+
8+
def peval1(): Expr[Unit] = '{
9+
def f(x: Int): Int = ~eval1('(f))
10+
}
11+
12+
def main(args: Array[String]): Unit = {
13+
val p = peval1()
14+
println(p.show)
15+
}
16+
17+
}

0 commit comments

Comments
 (0)