diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 6dca21f68b26..ddf3ef7ed765 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1142,14 +1142,10 @@ class TreeUnpickler(reader: TastyReader, val splice = splices(idx) val reifiedArgs = args.map(arg => if (arg.isTerm) new TreeExpr(arg) else new TreeType(arg)) if (isType) { - val quotedType = - if (reifiedArgs.isEmpty) splice.asInstanceOf[quoted.Type[_]] - else splice.asInstanceOf[Seq[Any] => quoted.Type[_]](reifiedArgs) + val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[_]](reifiedArgs) PickledQuotes.quotedTypeToTree(quotedType) } else { - val quotedExpr = - if (reifiedArgs.isEmpty) splice.asInstanceOf[quoted.Expr[_]] - else splice.asInstanceOf[Seq[Any] => quoted.Expr[_]](reifiedArgs) + val quotedExpr = splice.asInstanceOf[Seq[Any] => quoted.Expr[_]](reifiedArgs) PickledQuotes.quotedExprToTree(quotedExpr) } } diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index ae6cb049ef4f..32149a6ddaba 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -32,7 +32,6 @@ import dotty.tools.dotc.core.quoted._ * val x2 = ??? * ... * ~{ ... '{ ... x1 ... x2 ...} ... } - * ~{ ... /* no references to xi */ ... } * ... * } * ``` @@ -45,7 +44,6 @@ import dotty.tools.dotc.core.quoted._ * val x2 = ??? * ... * Hole(0 | x1, x2) - * Hole(1 | ) * ... * ]], * List( @@ -54,8 +52,7 @@ import dotty.tools.dotc.core.quoted._ * val x2$1 = args(1).asInstanceOf[Expr[T]] // can be asInstanceOf[Type[T]] * ... * { ... '{ ... x1$1.unary_~ ... x2$1.unary_~ ...} ... } - * }, - * { ... /* no references to xi */ ... } // optimized to not create lambda + * } * ) * ) * ``` @@ -69,12 +66,12 @@ import dotty.tools.dotc.core.quoted._ * ``` * to * ``` - * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Object = { (args: Seq[Any]) => { + * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Seq[Any] => Object = { (args: Seq[Any]) => { * val T1$1 = args(0).asInstanceOf[Type[T1]] * ... - * val x1$1 = args(..).asInstanceOf[X] + * val x1$1 = args(0).asInstanceOf[X] * ... - * val y1$1 = args(..).asInstanceOf[Expr[Y]] + * val y1$1 = args(1).asInstanceOf[Expr[Y]] * ... * { ... T1$1.unary_~ ... x ... '(y1$1.unary_~) ... } * } @@ -448,8 +445,6 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { * val y$1 = args(1).asInstanceOf[Expr[Any]] // or .asInstanceOf[Type[Any]] * { ... '{ ... x$1.unary_~ ... y$1.unary_~ ... } ... } * } - * or if the spliced subexpression has no captures it will be transformed to - * { ... '{ ... x$1.unary_~ ... y$1.unary_~ ... } ... } * * See: `capture` * @@ -462,19 +457,6 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { * } */ private def makeLambda(tree: Tree)(implicit ctx: Context): Tree = { - var treeWithoutCaptures: Tree = null - def transformWithCapturer(tree: Tree)(capturer: mutable.Map[Symbol, Tree] => Tree => Tree)(implicit ctx: Context): Tree = { - val captured = mutable.LinkedHashMap.empty[Symbol, Tree] - val captured2 = capturer(captured) - outer.enteredSyms.foreach(s => capturers.put(s, captured2)) - if (ctx.owner.owner.is(Macro)) - outer.enteredSyms.reverse.foreach(s => captured2(ref(s))) - val tree2 = transform(tree) - capturers --= outer.enteredSyms - if (captured.isEmpty) - treeWithoutCaptures = tree2 - seq(captured.result().valuesIterator.toList, tree2) - } def body(arg: Tree)(implicit ctx: Context): Tree = { var i = 0 transformWithCapturer(tree)( @@ -502,10 +484,18 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { val lambdaOwner = ctx.owner.ownersIterator.find(o => levelOf.getOrElse(o, level) == level).get val tpe = MethodType(defn.SeqType.appliedTo(defn.AnyType) :: Nil, tree.tpe.widen) val meth = ctx.newSymbol(lambdaOwner, UniqueName.fresh(nme.ANON_FUN), Synthetic | Method, tpe) - val closure = Closure(meth, tss => body(tss.head.head)(ctx.withOwner(meth)).changeOwner(ctx.owner, meth)) + Closure(meth, tss => body(tss.head.head)(ctx.withOwner(meth)).changeOwner(ctx.owner, meth)) + } - if (treeWithoutCaptures == null || ctx.owner.is(Macro)) closure - else treeWithoutCaptures + private def transformWithCapturer(tree: Tree)(capturer: mutable.Map[Symbol, Tree] => Tree => Tree)(implicit ctx: Context): Tree = { + val captured = mutable.LinkedHashMap.empty[Symbol, Tree] + val captured2 = capturer(captured) + outer.enteredSyms.foreach(s => capturers.put(s, captured2)) + if (ctx.owner.owner.is(Macro)) + outer.enteredSyms.reverse.foreach(s => captured2(ref(s))) + val tree2 = transform(tree) + capturers --= outer.enteredSyms + seq(captured.result().valuesIterator.toList, tree2) } /** Returns true if this tree will be captured by `makeLambda` */ diff --git a/tests/pos/i4380a.scala b/tests/pos/i4380a.scala new file mode 100644 index 000000000000..fefd5cc8b0f0 --- /dev/null +++ b/tests/pos/i4380a.scala @@ -0,0 +1,23 @@ +import scala.quoted._ + +object Test { + + trait Producer[A] { self => + def step(k: (A => Expr[Unit])): Expr[Unit] + } + + trait Foo[A] + case class Bar[A, B](producer: Producer[B], nestedf: B => Expr[Unit]) extends Foo[A] + + def meth[A](stream: Foo[Expr[A]]): Producer[Expr[A]] = { + stream match { + case Bar(producer, nestedf) => { + new Producer[Expr[A]] { + def step(k: Expr[A] => Expr[Unit]): Expr[Unit] = '{ + val adv: Unit => Unit = { _ => ~producer.step((el) => nestedf(el))} + } + } + } + } + } +} diff --git a/tests/pos/i4380b.scala b/tests/pos/i4380b.scala new file mode 100644 index 000000000000..b305780e0843 --- /dev/null +++ b/tests/pos/i4380b.scala @@ -0,0 +1,8 @@ +import scala.quoted._ + +object Test { + def step(k: (String => Expr[Unit])): Expr[Unit] = '() + def meth(): Unit = '{ + (i: Int) => ~step(el => '() ) + } +}