Skip to content

Unpickle quotes with the destination context #4242

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ object StdNames {
val COMPANION_CLASS_METHOD: N = "companion$class"
val BOUNDTYPE_ANNOT: N = "$boundType$"
val QUOTE: N = "'"
val TYPE_QUOTE: N = "type_'"
val TYPE_QUOTE: N = "type_'"
val PICKLED_QUOTE: N = "$quote"
val PICKLED_TYPE_QUOTE: N = "$typeQuote"
val TRAIT_SETTER_SEPARATOR: N = str.TRAIT_SETTER_SEPARATOR

// value types (and AnyRef) are all used as terms as well
Expand Down
11 changes: 8 additions & 3 deletions compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ object PickledQuotes {
val unpickled = unpickle(tastyBytes, expr.args)
unpickled match {
case PackageDef(_, (vdef: ValDef) :: Nil) =>
vdef.rhs.changeOwner(vdef.symbol, ctx.owner)
// vdef.rhs was unpickled with the current context. Symbols in vdef.rhs with
// owner vdef.symbol are unpickled as if their owner was ctx.owner. This optimization
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to give the name of the method that does this in TreeUnpickler.

// is done to avoid exponential transformation of nested pickled trees.
vdef.rhs
}
}

Expand All @@ -69,8 +72,10 @@ object PickledQuotes {
val unpickled = unpickle(tastyBytes, ttpe.args)
unpickled match {
case PackageDef(_, (vdef: ValDef) :: Nil) =>
// vdef.rhs was unpickled with the current context. Symbols in vdef.rhs with
// owner vdef.symbol are unpickled as if their owner was ctx.owner. This optimization
// is done to avoid exponential transformation of nested pickled trees.
vdef.rhs.asInstanceOf[TypeApply].args.head
.changeOwner(vdef.symbol, ctx.owner)
}
}

Expand All @@ -80,7 +85,7 @@ object PickledQuotes {
* `<type tree>` ==> `package _root_ { val $typeQuote: Any = null.asInstanceOf[<tree>] }`
*/
private def encapsulateQuote(tree: Tree)(implicit ctx: Context): Tree = {
val name = (if (tree.isTerm) "$quote" else "$typeQuote").toTermName
val name = if (tree.isTerm) nme.PICKLED_QUOTE else nme.PICKLED_TYPE_QUOTE
val sym = ctx.newSymbol(ctx.owner, name, Synthetic, defn.AnyType, coord = tree.pos)
val encoded =
if (tree.isTerm) tree
Expand Down
9 changes: 6 additions & 3 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -709,9 +709,12 @@ class TreeUnpickler(reader: TastyReader,
if (noRhs(end)) EmptyTree
else readLater(end, rdr => ctx => rdr.readTerm()(ctx))

def ValDef(tpt: Tree) =
ta.assignType(untpd.ValDef(sym.name.asTermName, tpt, readRhs(localCtx)), sym)

def ValDef(tpt: Tree) = {
val ctx2 =
if (sym.name != nme.PICKLED_QUOTE && sym.name != nme.PICKLED_TYPE_QUOTE) localCtx
else ctx.outer // Unpickle rhs with quote destination context. See PickledQuotes.{unpickleExpr|unpickleType}
ta.assignType(untpd.ValDef(sym.name.asTermName, tpt, readRhs(ctx2)), sym)
}
def DefDef(tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree) =
ta.assignType(
untpd.DefDef(sym.name.asTermName, tparams, vparamss, tpt, readRhs(localCtx)),
Expand Down
14 changes: 14 additions & 0 deletions tests/run-with-compiler/quote-owners-2.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
3
{
def ff: Int =
{
val a: List[Int] =
{
type T = List[Int]
val b: T = Nil.::[Int](3)
b: List[Int]
}
a.head: Int
}
ff: Int
}
24 changes: 24 additions & 0 deletions tests/run-with-compiler/quote-owners-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import quoted._
import dotty.tools.dotc.quoted.Toolbox._

object Test {
def main(args: Array[String]): Unit = {
val q = f(g(Type.IntTag))
println(q.run)
println(q.show)
}

def f(t: Type[List[Int]]): Expr[Int] = '{
def ff: Int = {
val a: ~t = {
type T = ~t
val b: T = 3 :: Nil
b
}
a.head
}
ff
}

def g[T](a: Type[T]): Type[List[T]] = '[List[~a]]
}
9 changes: 9 additions & 0 deletions tests/run-with-compiler/quote-owners.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
9
{
def ff: Int =
{
val a: Int = 9
a.+(0)
}
ff: Int
}
22 changes: 22 additions & 0 deletions tests/run-with-compiler/quote-owners.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import quoted._
import dotty.tools.dotc.quoted.Toolbox._

object Test {
def main(args: Array[String]): Unit = {
val q = f
println(q.run)
println(q.show)
}

def f: Expr[Int] = '{
def ff: Int = {
~g
}
ff
}

def g: Expr[Int] = '{
val a = 9
a + 0
}
}