Skip to content

Commit

Permalink
Merge pull request scala#6949 from dotty-staging/move-quote-beta-redu…
Browse files Browse the repository at this point in the history
…ction-to-context

 Move quote beta-reduction to QuoteContext
  • Loading branch information
nicolasstucki authored Jul 31, 2019
2 parents 9e589a4 + 0abeb8d commit 4f071a0
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 46 deletions.
29 changes: 0 additions & 29 deletions compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ object PickledQuotes {
}
forceAndCleanArtefacts.transform(unpickled)
case expr: TastyTreeExpr[Tree] @unchecked => healOwner(expr.tree)
case expr: FunctionAppliedTo[_] =>
functionAppliedTo(quotedExprToTree(expr.f), expr.args.map(arg => quotedExprToTree(arg(new scala.quoted.QuoteContext(ReflectionImpl(ctx))))).toList)
}

/** Transform the expression into its fully spliced TypeTree */
Expand Down Expand Up @@ -127,33 +125,6 @@ object PickledQuotes {
tree
}

private def functionAppliedTo(fn: Tree, args: List[Tree])(implicit ctx: Context): Tree = {
val (argVals, argRefs) = args.map(arg => arg.tpe match {
case tpe: SingletonType if isIdempotentExpr(arg) => (Nil, arg)
case _ =>
val argVal = SyntheticValDef(NameKinds.UniqueName.fresh("x".toTermName), arg).withSpan(arg.span)
(argVal :: Nil, ref(argVal.symbol))
}).unzip
def rec(fn: Tree): Tree = fn match {
case Inlined(call, bindings, expansion) =>
// this case must go before closureDef to avoid dropping the inline node
cpy.Inlined(fn)(call, bindings, rec(expansion))
case closureDef(ddef) =>
val paramSyms = ddef.vparamss.head.map(param => param.symbol)
val paramToVals = paramSyms.zip(argRefs).toMap
new TreeTypeMap(
oldOwners = ddef.symbol :: Nil,
newOwners = ctx.owner :: Nil,
treeMap = tree => paramToVals.get(tree.symbol).map(_.withSpan(tree.span)).getOrElse(tree)
).transform(ddef.rhs)
case Block(stats, expr) =>
seq(stats, rec(expr)).withSpan(fn.span)
case _ =>
fn.select(nme.apply).appliedToArgs(argRefs).withSpan(fn.span)
}
seq(argVals.flatten, rec(fn))
}

/** Make sure that the owner of this tree is `ctx.owner` */
private def healOwner(tree: Tree)(implicit ctx: Context): Tree = {
val getCurrentOwner = new TreeAccumulator[Option[Symbol]] {
Expand Down
36 changes: 33 additions & 3 deletions compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package dotty.tools.dotc
package tastyreflect

import dotty.tools.dotc.ast.Trees.SeqLiteral
import dotty.tools.dotc.ast.{Trees, tpd, untpd}
import dotty.tools.dotc.ast.tpd.TreeOps
import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.{TreeTypeMap, Trees, tpd, untpd}
import dotty.tools.dotc.typer.{Implicits, Typer}
import dotty.tools.dotc.core._
import dotty.tools.dotc.core.Flags._
import dotty.tools.dotc.core.StdNames.nme
import dotty.tools.dotc.core.quoted.PickledQuotes
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.Decorators._
import dotty.tools.dotc.core.Types.SingletonType
import dotty.tools.dotc.tastyreflect.FromSymbol.{definitionFromSym, packageDefFromSym}
import dotty.tools.dotc.parsing.Parsers.Parser
import dotty.tools.dotc.typer.Implicits.{AmbiguousImplicits, DivergingImplicit, NoMatchingImplicits, SearchFailure, SearchFailureType}
Expand All @@ -19,6 +19,7 @@ import dotty.tools.dotc.util.{SourceFile, SourcePosition, Spans}
import scala.tasty.reflect.Kernel

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

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

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

def betaReduce(fn: Term, args: List[Term]) given (ctx: Context): Term = {
val (argVals0, argRefs0) = args.foldLeft((List.empty[ValDef], List.empty[Tree])) { case ((acc1, acc2), arg) => arg.tpe match {
case tpe: SingletonType if isIdempotentExpr(arg) => (acc1, arg :: acc2)
case _ =>
val argVal = SyntheticValDef(NameKinds.UniqueName.fresh("x".toTermName), arg).withSpan(arg.span)
(argVal :: acc1, ref(argVal.symbol) :: acc2)
}}
val argVals = argVals0.reverse
val argRefs = argRefs0.reverse
def rec(fn: Tree): Tree = fn match {
case Inlined(call, bindings, expansion) =>
// this case must go before closureDef to avoid dropping the inline node
cpy.Inlined(fn)(call, bindings, rec(expansion))
case closureDef(ddef) =>
val paramSyms = ddef.vparamss.head.map(param => param.symbol)
val paramToVals = paramSyms.zip(argRefs).toMap
new TreeTypeMap(
oldOwners = ddef.symbol :: Nil,
newOwners = ctx.owner :: Nil,
treeMap = tree => paramToVals.get(tree.symbol).map(_.withSpan(tree.span)).getOrElse(tree)
).transform(ddef.rhs)
case Block(stats, expr) =>
seq(stats, rec(expr)).withSpan(fn.span)
case _ =>
fn.select(nme.apply).appliedToArgs(argRefs).withSpan(fn.span)
}
seq(argVals, rec(fn))
}

//
// HELPERS
//
Expand Down
24 changes: 10 additions & 14 deletions library/src/scala/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,20 @@ package quoted {
/** Converts a tuple `(T1, ..., Tn)` to `(Expr[T1], ..., Expr[Tn])` */
type TupleOfExpr[Tup <: Tuple] = Tuple.Map[Tup, [X] =>> given QuoteContext => Expr[X]]

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

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

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

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

}
}
5 changes: 5 additions & 0 deletions library/src/scala/tasty/reflect/Kernel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1538,4 +1538,9 @@ trait Kernel {
*/
def searchImplicit(tpe: Type) given (ctx: Context): ImplicitSearchResult

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

}

0 comments on commit 4f071a0

Please sign in to comment.