diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index a6543572b23f..360a10de5968 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index 7f6341b70b44..e526bc7473d1 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -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 + // is done to avoid exponential transformation of nested pickled trees. + vdef.rhs } } @@ -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) } } @@ -80,7 +85,7 @@ object PickledQuotes { * `` ==> `package _root_ { val $typeQuote: Any = null.asInstanceOf[] }` */ 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 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 6dca21f68b26..7b07269a3abf 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -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)), diff --git a/tests/run-with-compiler/quote-owners-2.check b/tests/run-with-compiler/quote-owners-2.check new file mode 100644 index 000000000000..fee34077c6f9 --- /dev/null +++ b/tests/run-with-compiler/quote-owners-2.check @@ -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 +} diff --git a/tests/run-with-compiler/quote-owners-2.scala b/tests/run-with-compiler/quote-owners-2.scala new file mode 100644 index 000000000000..a31338f30ac5 --- /dev/null +++ b/tests/run-with-compiler/quote-owners-2.scala @@ -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]] +} diff --git a/tests/run-with-compiler/quote-owners.check b/tests/run-with-compiler/quote-owners.check new file mode 100644 index 000000000000..8b1f473d369a --- /dev/null +++ b/tests/run-with-compiler/quote-owners.check @@ -0,0 +1,9 @@ +9 +{ + def ff: Int = + { + val a: Int = 9 + a.+(0) + } + ff: Int +} diff --git a/tests/run-with-compiler/quote-owners.scala b/tests/run-with-compiler/quote-owners.scala new file mode 100644 index 000000000000..1ccadf592d0a --- /dev/null +++ b/tests/run-with-compiler/quote-owners.scala @@ -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 + } +}