Skip to content

Commit 4f071a0

Browse files
Merge pull request #6949 from dotty-staging/move-quote-beta-reduction-to-context
Move quote beta-reduction to QuoteContext
2 parents 9e589a4 + 0abeb8d commit 4f071a0

File tree

4 files changed

+48
-46
lines changed

4 files changed

+48
-46
lines changed

compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ object PickledQuotes {
4747
}
4848
forceAndCleanArtefacts.transform(unpickled)
4949
case expr: TastyTreeExpr[Tree] @unchecked => healOwner(expr.tree)
50-
case expr: FunctionAppliedTo[_] =>
51-
functionAppliedTo(quotedExprToTree(expr.f), expr.args.map(arg => quotedExprToTree(arg(new scala.quoted.QuoteContext(ReflectionImpl(ctx))))).toList)
5250
}
5351

5452
/** Transform the expression into its fully spliced TypeTree */
@@ -127,33 +125,6 @@ object PickledQuotes {
127125
tree
128126
}
129127

130-
private def functionAppliedTo(fn: Tree, args: List[Tree])(implicit ctx: Context): Tree = {
131-
val (argVals, argRefs) = args.map(arg => arg.tpe match {
132-
case tpe: SingletonType if isIdempotentExpr(arg) => (Nil, arg)
133-
case _ =>
134-
val argVal = SyntheticValDef(NameKinds.UniqueName.fresh("x".toTermName), arg).withSpan(arg.span)
135-
(argVal :: Nil, ref(argVal.symbol))
136-
}).unzip
137-
def rec(fn: Tree): Tree = fn match {
138-
case Inlined(call, bindings, expansion) =>
139-
// this case must go before closureDef to avoid dropping the inline node
140-
cpy.Inlined(fn)(call, bindings, rec(expansion))
141-
case closureDef(ddef) =>
142-
val paramSyms = ddef.vparamss.head.map(param => param.symbol)
143-
val paramToVals = paramSyms.zip(argRefs).toMap
144-
new TreeTypeMap(
145-
oldOwners = ddef.symbol :: Nil,
146-
newOwners = ctx.owner :: Nil,
147-
treeMap = tree => paramToVals.get(tree.symbol).map(_.withSpan(tree.span)).getOrElse(tree)
148-
).transform(ddef.rhs)
149-
case Block(stats, expr) =>
150-
seq(stats, rec(expr)).withSpan(fn.span)
151-
case _ =>
152-
fn.select(nme.apply).appliedToArgs(argRefs).withSpan(fn.span)
153-
}
154-
seq(argVals.flatten, rec(fn))
155-
}
156-
157128
/** Make sure that the owner of this tree is `ctx.owner` */
158129
private def healOwner(tree: Tree)(implicit ctx: Context): Tree = {
159130
val getCurrentOwner = new TreeAccumulator[Option[Symbol]] {

compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
package dotty.tools.dotc
22
package tastyreflect
33

4-
import dotty.tools.dotc.ast.Trees.SeqLiteral
5-
import dotty.tools.dotc.ast.{Trees, tpd, untpd}
6-
import dotty.tools.dotc.ast.tpd.TreeOps
4+
import dotty.tools.dotc.ast.Trees._
5+
import dotty.tools.dotc.ast.{TreeTypeMap, Trees, tpd, untpd}
76
import dotty.tools.dotc.typer.{Implicits, Typer}
87
import dotty.tools.dotc.core._
98
import dotty.tools.dotc.core.Flags._
109
import dotty.tools.dotc.core.StdNames.nme
1110
import dotty.tools.dotc.core.quoted.PickledQuotes
1211
import dotty.tools.dotc.core.Symbols._
1312
import dotty.tools.dotc.core.Decorators._
13+
import dotty.tools.dotc.core.Types.SingletonType
1414
import dotty.tools.dotc.tastyreflect.FromSymbol.{definitionFromSym, packageDefFromSym}
1515
import dotty.tools.dotc.parsing.Parsers.Parser
1616
import dotty.tools.dotc.typer.Implicits.{AmbiguousImplicits, DivergingImplicit, NoMatchingImplicits, SearchFailure, SearchFailureType}
@@ -19,6 +19,7 @@ import dotty.tools.dotc.util.{SourceFile, SourcePosition, Spans}
1919
import scala.tasty.reflect.Kernel
2020

2121
class KernelImpl(val rootContext: core.Contexts.Context) extends Kernel {
22+
import tpd._
2223

2324
private implicit def ctx: core.Contexts.Context = rootContext
2425

@@ -1894,6 +1895,35 @@ class KernelImpl(val rootContext: core.Contexts.Context) extends Kernel {
18941895
case _ => None
18951896
}
18961897

1898+
def betaReduce(fn: Term, args: List[Term]) given (ctx: Context): Term = {
1899+
val (argVals0, argRefs0) = args.foldLeft((List.empty[ValDef], List.empty[Tree])) { case ((acc1, acc2), arg) => arg.tpe match {
1900+
case tpe: SingletonType if isIdempotentExpr(arg) => (acc1, arg :: acc2)
1901+
case _ =>
1902+
val argVal = SyntheticValDef(NameKinds.UniqueName.fresh("x".toTermName), arg).withSpan(arg.span)
1903+
(argVal :: acc1, ref(argVal.symbol) :: acc2)
1904+
}}
1905+
val argVals = argVals0.reverse
1906+
val argRefs = argRefs0.reverse
1907+
def rec(fn: Tree): Tree = fn match {
1908+
case Inlined(call, bindings, expansion) =>
1909+
// this case must go before closureDef to avoid dropping the inline node
1910+
cpy.Inlined(fn)(call, bindings, rec(expansion))
1911+
case closureDef(ddef) =>
1912+
val paramSyms = ddef.vparamss.head.map(param => param.symbol)
1913+
val paramToVals = paramSyms.zip(argRefs).toMap
1914+
new TreeTypeMap(
1915+
oldOwners = ddef.symbol :: Nil,
1916+
newOwners = ctx.owner :: Nil,
1917+
treeMap = tree => paramToVals.get(tree.symbol).map(_.withSpan(tree.span)).getOrElse(tree)
1918+
).transform(ddef.rhs)
1919+
case Block(stats, expr) =>
1920+
seq(stats, rec(expr)).withSpan(fn.span)
1921+
case _ =>
1922+
fn.select(nme.apply).appliedToArgs(argRefs).withSpan(fn.span)
1923+
}
1924+
seq(argVals, rec(fn))
1925+
}
1926+
18971927
//
18981928
// HELPERS
18991929
//

library/src/scala/quoted/Expr.scala

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,20 @@ package quoted {
3535
/** Converts a tuple `(T1, ..., Tn)` to `(Expr[T1], ..., Expr[Tn])` */
3636
type TupleOfExpr[Tup <: Tuple] = Tuple.Map[Tup, [X] =>> given QuoteContext => Expr[X]]
3737

38-
implicit class AsFunction[F, Args <: Tuple, R](f: Expr[F]) given (tf: TupledFunction[F, Args => R]) {
38+
implicit class AsFunction[F, Args <: Tuple, R](f: Expr[F]) given (tf: TupledFunction[F, Args => R], qctx: QuoteContext) {
3939
/** Beta-reduces the function appication. Generates the an expression only containing the body of the function */
40-
def apply[G] given (tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]]): G =
41-
tg.untupled(args => new FunctionAppliedTo[R](f, args.toArray.map(_.asInstanceOf[QuoteContext => Expr[_]])))
40+
def apply[G] given (tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]]): G = {
41+
import qctx.tasty._
42+
tg.untupled(args => qctx.tasty.kernel.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
43+
}
4244
}
4345

44-
implicit class AsContextualFunction[F, Args <: Tuple, R](f: Expr[F]) given (tf: TupledFunction[F, given Args => R]) {
46+
implicit class AsContextualFunction[F, Args <: Tuple, R](f: Expr[F]) given (tf: TupledFunction[F, given Args => R], qctx: QuoteContext) {
4547
/** Beta-reduces the function appication. Generates the an expression only containing the body of the function */
46-
def apply[G] given (tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]]): G =
47-
tg.untupled(args => new FunctionAppliedTo[R](f, args.toArray.map(_.asInstanceOf[QuoteContext => Expr[_]])))
48+
def apply[G] given (tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]]): G = {
49+
import qctx.tasty._
50+
tg.untupled(args => qctx.tasty.kernel.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
51+
}
4852
}
4953

5054
/** Returns a null expresssion equivalent to `'{null}` */
@@ -93,13 +97,5 @@ package internal {
9397
override def toString: String = s"Expr(<tasty tree>)"
9498
}
9599

96-
// TODO Use a List in FunctionAppliedTo(val f: Expr[_], val args: List[Expr[_]])
97-
// FIXME: Having the List in the code above trigers an assertion error while testing dotty.tools.dotc.reporting.ErrorMessagesTests.i3187
98-
// This test does redefine `scala.collection`. Further investigation is needed.
99-
/** An Expr representing `'{($f).apply($x1, ..., $xn)}` but it is beta-reduced when the closure is known */
100-
final class FunctionAppliedTo[+R](val f: Expr[_], val args: Array[QuoteContext => Expr[_]]) extends Expr[R] {
101-
override def toString: String = s"Expr($f <applied to> ${args.toList})"
102-
}
103-
104100
}
105101
}

library/src/scala/tasty/reflect/Kernel.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,4 +1538,9 @@ trait Kernel {
15381538
*/
15391539
def searchImplicit(tpe: Type) given (ctx: Context): ImplicitSearchResult
15401540

1541+
/** Inline fn if it is an explicit closure possibly nested inside the expression of a block.
1542+
* Otherwise apply the arguments to the closure.
1543+
*/
1544+
def betaReduce(f: Term, args: List[Term]) given (ctx: Context): Term
1545+
15411546
}

0 commit comments

Comments
 (0)