-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix #4456: Pickle quote before compiling #4457
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,26 @@ import scala.reflect.ClassTag | |
object PickledQuotes { | ||
import tpd._ | ||
|
||
/** Pickle the quote into strings */ | ||
/** Pickle the tree of the a quoted.Expr */ | ||
def pickleExpr(tree: Tree)(implicit ctx: Context): scala.quoted.Expr[Any] = { | ||
// Check that there are no free variables | ||
new TreeTraverser { | ||
private val definedHere = scala.collection.mutable.Set.empty[Symbol] | ||
def traverse(tree: tpd.Tree)(implicit ctx: Context): Unit = tree match { | ||
case tree: Ident if tree.symbol.exists && !definedHere(tree.symbol) => | ||
throw new scala.quoted.FreeVariableError(tree.name.toString) | ||
case tree: DefTree => | ||
definedHere += tree.symbol | ||
traverseChildren(tree) | ||
case _ => | ||
traverseChildren(tree) | ||
} | ||
}.traverse(tree) | ||
val pickled = pickleQuote(tree) | ||
scala.runtime.quoted.Unpickler.unpickleExpr(pickled, Nil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // ignore, I have just went through the second unit test and you do what I had in mind. |
||
} | ||
|
||
/** Pickle the tree of the quote into strings */ | ||
def pickleQuote(tree: Tree)(implicit ctx: Context): scala.runtime.quoted.Unpickler.Pickled = { | ||
if (ctx.reporter.hasErrors) Nil | ||
else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,7 +37,8 @@ object Exprs { | |
} | ||
|
||
/** An Expr backed by a tree. Only the current compiler trees are allowed. */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarify what we mean by "current compiler"? |
||
final class TreeExpr[Tree](val tree: Tree) extends quoted.Expr[Any] { | ||
final class TreeExpr[Tree](val tree: Tree, pickle: => Expr[_]) extends quoted.Expr[Any] { | ||
def pickled[T]: Expr[T] = pickle.asInstanceOf[Expr[T]] | ||
override def toString: String = s"Expr(<raw>)" | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package scala.quoted | ||
|
||
class FreeVariableError(val name: String) extends QuoteError("Free variable " + name + " could not be handled") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import scala.quoted._ | ||
|
||
import dotty.tools.dotc.quoted.Toolbox._ | ||
|
||
object Macros { | ||
inline def foo(i: => Int): Int = ~{ | ||
val y: Int = ('(i)).run | ||
y.toExpr | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import Macros._ | ||
object Test { | ||
def main(args: Array[String]): Unit = { | ||
val x = 3 | ||
println(foo(x)) // error | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
1 | ||
4 | ||
5 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import scala.quoted._ | ||
|
||
import dotty.tools.dotc.quoted.Toolbox._ | ||
|
||
object Macros { | ||
inline def foo(i: => Int): Int = ~{ | ||
val y: Int = ('(i)).run | ||
y.toExpr | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import Macros._ | ||
object Test { | ||
def main(args: Array[String]): Unit = { | ||
println(foo(1)) | ||
println(foo(1 + 3)) | ||
val x = 3 | ||
println(foo { | ||
val x = 5 | ||
x | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
"> 3" | ||
"> 12" | ||
(x: scala.Int) => "> ".+(y).apply(3) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import scala.quoted._ | ||
|
||
import dotty.tools.dotc.quoted.Toolbox._ | ||
|
||
object Macros { | ||
inline def foo(f: => Int => String): String = ~bar('(f)) | ||
def bar(f: Expr[Int => String]): Expr[String] = { | ||
try { | ||
val y: Int => String = f.run | ||
val res = y(3).toExpr // evaluate at compile time | ||
res.show.toExpr | ||
} catch { | ||
case ex: scala.quoted.FreeVariableError => | ||
val res = ('((~f)(3))) // evaluate at run time | ||
res.show.toExpr | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import Macros._ | ||
object Test { | ||
def main(args: Array[String]): Unit = { | ||
println(foo(x => "> " + x)) | ||
println(foo(x => "> " + 4 * x)) | ||
val y = 9 | ||
println(foo(x => "> " + y)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the
a
:P