From 5db3b72eea04afc0e2e6b2b2bafe5288ba48d3cb Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Fri, 28 Jun 2019 15:32:36 +0200 Subject: [PATCH 1/7] Rename lambda to closure --- .../tools/dotc/tastyreflect/KernelImpl.scala | 16 +++++------ .../scala/internal/quoted/Matcher.scala | 2 +- library/src/scala/tasty/reflect/Core.scala | 17 +++++++++--- library/src/scala/tasty/reflect/Kernel.scala | 27 +++++++++++++------ .../src/scala/tasty/reflect/Printers.scala | 12 +++++---- library/src/scala/tasty/reflect/TreeOps.scala | 26 +++++++++--------- .../src/scala/tasty/reflect/TreeUtils.scala | 9 +++---- 7 files changed, 66 insertions(+), 43 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala index e1cfde7d7fb5..0a79d0dc78e1 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala @@ -506,21 +506,21 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util. def Inlined_copy(original: Tree)(call: Option[Term | TypeTree], bindings: List[Definition], expansion: Term)(implicit ctx: Context): Inlined = tpd.cpy.Inlined(original)(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], expansion) - type Lambda = tpd.Closure + type Closure = tpd.Closure - def matchLambda(x: Term)(implicit ctx: Context): Option[Lambda] = x match { + def matchClosure(x: Term)(implicit ctx: Context): Option[Closure] = x match { case x: tpd.Closure => Some(x) case _ => None } - def Lambda_meth(self: Lambda)(implicit ctx: Context): Term = self.meth - def Lambda_tptOpt(self: Lambda)(implicit ctx: Context): Option[TypeTree] = optional(self.tpt) + def Closure_meth(self: Closure)(implicit ctx: Context): Term = self.meth + def Closure_tpeOpt(self: Closure)(implicit ctx: Context): Option[Type] = optional(self.tpt).map(_.tpe) - def Lambda_apply(meth: Term, tpt: Option[TypeTree])(implicit ctx: Context): Lambda = - withDefaultPos(ctx => tpd.Closure(Nil, meth, tpt.getOrElse(tpd.EmptyTree))(ctx)) + def Closure_apply(meth: Term, tpe: Option[Type])(implicit ctx: Context): Closure = + withDefaultPos(ctx => tpd.Closure(Nil, meth, tpe.map(tpd.TypeTree(_)).getOrElse(tpd.EmptyTree))(ctx)) - def Lambda_copy(original: Tree)(meth: Tree, tpt: Option[TypeTree])(implicit ctx: Context): Lambda = - tpd.cpy.Closure(original)(Nil, meth, tpt.getOrElse(tpd.EmptyTree)) + def Closure_copy(original: Tree)(meth: Tree, tpe: Option[Type])(implicit ctx: Context): Closure = + tpd.cpy.Closure(original)(Nil, meth, tpe.map(tpd.TypeTree(_)).getOrElse(tpd.EmptyTree)) type If = tpd.If diff --git a/library/src-bootstrapped/scala/internal/quoted/Matcher.scala b/library/src-bootstrapped/scala/internal/quoted/Matcher.scala index bb3d0c6b4e62..a44cc7712dfc 100644 --- a/library/src-bootstrapped/scala/internal/quoted/Matcher.scala +++ b/library/src-bootstrapped/scala/internal/quoted/Matcher.scala @@ -207,7 +207,7 @@ object Matcher { tpt1 =#= tpt2 && withEnv(rhsEnv)(rhs1 =#= rhs2) - case (Lambda(_, tpt1), Lambda(_, tpt2)) => + case (Closure(_, tpt1), Closure(_, tpt2)) => // TODO match tpt1 with tpt2? matched diff --git a/library/src/scala/tasty/reflect/Core.scala b/library/src/scala/tasty/reflect/Core.scala index 047d2ffd85a5..f2069832a541 100644 --- a/library/src/scala/tasty/reflect/Core.scala +++ b/library/src/scala/tasty/reflect/Core.scala @@ -26,7 +26,7 @@ package scala.tasty.reflect * | +- Typed * | +- Assign * | +- Block - * | +- Lambda + * | +- Closure * | +- If * | +- Match * | +- ImpliedMatch @@ -200,8 +200,19 @@ trait Core { /** Tree representing a block `{ ... }` in the source code */ type Block = kernel.Block - /** Tree representing a lambda `(...) => ...` in the source code */ - type Lambda = kernel.Lambda + /** A lambda `(...) => ...` in the source code is represented as + * a local method and a closure: + * + * { + * def m(...) = ... + * closure(m) + * } + * + * While a function literal is usually a block with the two parts, + * in the Dotty compiler, the two parts may locate in a flattened + * block and may not be consecutive. + */ + type Closure = kernel.Closure /** Tree representing an if/then/else `if (...) ... else ...` in the source code */ type If = kernel.If diff --git a/library/src/scala/tasty/reflect/Kernel.scala b/library/src/scala/tasty/reflect/Kernel.scala index ec3420b63b6c..33cd76f6f76e 100644 --- a/library/src/scala/tasty/reflect/Kernel.scala +++ b/library/src/scala/tasty/reflect/Kernel.scala @@ -25,7 +25,7 @@ package scala.tasty.reflect * | +- Typed * | +- Assign * | +- Block - * | +- Lambda + * | +- Closure * | +- If * | +- Match * | +- ImpliedMatch @@ -436,16 +436,27 @@ trait Kernel { def Block_apply(stats: List[Statement], expr: Term)(implicit ctx: Context): Block def Block_copy(original: Tree)(stats: List[Statement], expr: Term)(implicit ctx: Context): Block - /** Tree representing a lambda `(...) => ...` in the source code */ - type Lambda <: Term + /** A lambda `(...) => ...` in the source code is represented as + * a local method and a closure: + * + * { + * def m(...) = ... + * closure(m) + * } + * + * While a function literal is usually a block with the two parts, + * in the Dotty compiler, the two parts may locate in a flattened + * block and may not be consecutive. + */ + type Closure <: Term - def matchLambda(tree: Tree)(implicit ctx: Context): Option[Lambda] + def matchClosure(tree: Tree)(implicit ctx: Context): Option[Closure] - def Lambda_meth(self: Lambda)(implicit ctx: Context): Term - def Lambda_tptOpt(self: Lambda)(implicit ctx: Context): Option[TypeTree] + def Closure_meth(self: Closure)(implicit ctx: Context): Term + def Closure_tpeOpt(self: Closure)(implicit ctx: Context): Option[Type] - def Lambda_apply(meth: Term, tpt: Option[TypeTree])(implicit ctx: Context): Lambda - def Lambda_copy(original: Tree)(meth: Tree, tpt: Option[TypeTree])(implicit ctx: Context): Lambda + def Closure_apply(meth: Term, tpe: Option[Type])(implicit ctx: Context): Closure + def Closure_copy(original: Tree)(meth: Tree, tpe: Option[Type])(implicit ctx: Context): Closure /** Tree representing an if/then/else `if (...) ... else ...` in the source code */ type If <: Term diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index 1a6c72351b42..50dd64596f2d 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -201,8 +201,8 @@ trait Printers this += "Block(" ++= stats += ", " += expr += ")" case If(cond, thenp, elsep) => this += "If(" += cond += ", " += thenp += ", " += elsep += ")" - case Lambda(meth, tpt) => - this += "Lambda(" += meth += ", " += tpt += ")" + case Closure(meth, tpt) => + this += "Closure(" += meth += ", " += tpt += ")" case Match(selector, cases) => this += "Match(" += selector += ", " ++= cases += ")" case ImpliedMatch(cases) => @@ -406,6 +406,7 @@ trait Printers private implicit class TypeOps(buff: Buffer) { def +=(x: TypeOrBounds): Buffer = { visitType(x); buff } + def +=(x: Option[TypeOrBounds]): Buffer = { visitOption(x, visitType); buff } def ++=(x: List[TypeOrBounds]): Buffer = { visitList(x, visitType); buff } } @@ -911,7 +912,7 @@ trait Printers case Inlined(_, bindings, expansion) => printFlatBlock(bindings, expansion) - case Lambda(meth, tpt) => + case Closure(meth, tpt) => // Printed in by it's DefDef this @@ -1019,11 +1020,12 @@ trait Printers val (stats1, expr1) = flatBlock(stats, expr) // Remove Lambda nodes, lambdas are printed by their definition val stats2 = stats1.filter { - case Lambda(_, _) => false + case Closure(_, _) => false + case IsTypeDef(tree) => !tree.symbol.annots.exists(_.symbol.owner.fullName == "scala.internal.Quoted$.quoteTypeTag") case _ => true } val (stats3, expr3) = expr1 match { - case Lambda(_, _) => + case Closure(_, _) => val init :+ last = stats2 (init, last) case _ => (stats2, expr1) diff --git a/library/src/scala/tasty/reflect/TreeOps.scala b/library/src/scala/tasty/reflect/TreeOps.scala index adf164a7caf5..7c2635651621 100644 --- a/library/src/scala/tasty/reflect/TreeOps.scala +++ b/library/src/scala/tasty/reflect/TreeOps.scala @@ -552,26 +552,26 @@ trait TreeOps extends Core { def expr(implicit ctx: Context): Term = kernel.Block_expr(self) } - object IsLambda { - /** Matches any Lambda and returns it */ - def unapply(tree: Tree)(implicit ctx: Context): Option[Lambda] = kernel.matchLambda(tree) + object IsClosure { + /** Matches any Closure and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Closure] = kernel.matchClosure(tree) } - object Lambda { + object Closure { - def apply(meth: Term, tpt: Option[TypeTree])(implicit ctx: Context): Lambda = - kernel.Lambda_apply(meth, tpt) + def apply(meth: Term, tpt: Option[Type])(implicit ctx: Context): Closure = + kernel.Closure_apply(meth, tpt) - def copy(original: Tree)(meth: Tree, tpt: Option[TypeTree])(implicit ctx: Context): Lambda = - kernel.Lambda_copy(original)(meth, tpt) + def copy(original: Tree)(meth: Tree, tpt: Option[Type])(implicit ctx: Context): Closure = + kernel.Closure_copy(original)(meth, tpt) - def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Option[TypeTree])] = - kernel.matchLambda(tree).map(x => (x.meth, x.tptOpt)) + def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Option[Type])] = + kernel.matchClosure(tree).map(x => (x.meth, x.tpeOpt)) } - implicit class LambdaAPI(self: Lambda) { - def meth(implicit ctx: Context): Term = kernel.Lambda_meth(self) - def tptOpt(implicit ctx: Context): Option[TypeTree] = kernel.Lambda_tptOpt(self) + implicit class ClosureAPI(self: Closure) { + def meth(implicit ctx: Context): Term = kernel.Closure_meth(self) + def tpeOpt(implicit ctx: Context): Option[Type] = kernel.Closure_tpeOpt(self) } object IsIf { diff --git a/library/src/scala/tasty/reflect/TreeUtils.scala b/library/src/scala/tasty/reflect/TreeUtils.scala index 7146e5ff1269..8f7f88235586 100644 --- a/library/src/scala/tasty/reflect/TreeUtils.scala +++ b/library/src/scala/tasty/reflect/TreeUtils.scala @@ -48,9 +48,8 @@ trait TreeUtils foldTree(foldTree(foldTree(x, cond), thenp), elsep) case While(cond, body) => foldTree(foldTree(x, cond), body) - case Lambda(meth, tpt) => - val a = foldTree(x, meth) - tpt.fold(a)(b => foldTree(a, b)) + case Closure(meth, tpt) => + foldTree(x, meth) case Match(selector, cases) => foldTrees(foldTree(x, selector), cases) case Return(expr) => @@ -193,8 +192,8 @@ trait TreeUtils Block.copy(tree)(transformStats(stats), transformTerm(expr)) case If(cond, thenp, elsep) => If.copy(tree)(transformTerm(cond), transformTerm(thenp), transformTerm(elsep)) - case Lambda(meth, tpt) => - Lambda.copy(tree)(transformTerm(meth), tpt.map(x => transformTypeTree(x))) + case Closure(meth, tpt) => + Closure.copy(tree)(transformTerm(meth), tpt) case Match(selector, cases) => Match.copy(tree)(transformTerm(selector), transformCaseDefs(cases)) case Return(expr) => From c660d4ca13d168b01a18a77cda769e4bd024123d Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Sat, 29 Jun 2019 13:58:40 +0200 Subject: [PATCH 2/7] Add extractor for function literals --- library/src/scala/tasty/reflect/TreeOps.scala | 19 +++++++++++++++++++ .../run-macros/reflect-lambda/assert_1.scala | 18 ++++++++++++++++++ tests/run-macros/reflect-lambda/test_2.scala | 14 ++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 tests/run-macros/reflect-lambda/assert_1.scala create mode 100644 tests/run-macros/reflect-lambda/test_2.scala diff --git a/library/src/scala/tasty/reflect/TreeOps.scala b/library/src/scala/tasty/reflect/TreeOps.scala index 7c2635651621..1529d6f7b7be 100644 --- a/library/src/scala/tasty/reflect/TreeOps.scala +++ b/library/src/scala/tasty/reflect/TreeOps.scala @@ -574,6 +574,25 @@ trait TreeOps extends Core { def tpeOpt(implicit ctx: Context): Option[Type] = kernel.Closure_tpeOpt(self) } + /** A lambda `(...) => ...` in the source code is represented as + * a local method and a closure: + * + * { + * def m(...) = ... + * closure(m) + * } + * + */ + object Lambda { + def unapply(tree: Tree)(implicit ctx: Context): Option[(List[ValDef], Term)] = tree match { + case Block((ddef @ DefDef(_, _, params :: Nil, _, Some(body))) :: Nil, Closure(meth, _)) + if ddef.symbol == meth.symbol => + Some(params, body) + + case _ => None + } + } + object IsIf { /** Matches any If and returns it */ def unapply(tree: Tree)(implicit ctx: Context): Option[If] = kernel.matchIf(tree) diff --git a/tests/run-macros/reflect-lambda/assert_1.scala b/tests/run-macros/reflect-lambda/assert_1.scala new file mode 100644 index 000000000000..c439ceeacbe3 --- /dev/null +++ b/tests/run-macros/reflect-lambda/assert_1.scala @@ -0,0 +1,18 @@ +import scala.quoted._ +import scala.tasty._ + +object lib { + + inline def assert(condition: => Boolean): Unit = ${ assertImpl('condition, '{""}) } + + def assertImpl(cond: Expr[Boolean], clue: Expr[Any])(implicit refl: Reflection): Expr[Unit] = { + import refl._ + import util._ + + cond.unseal.underlyingArgument match { + case t @ Apply(Select(lhs, op), Lambda(param :: Nil, Apply(Select(a, "=="), b :: Nil)) :: Nil) + if a.symbol == param.symbol || b.symbol == param.symbol => + '{ scala.Predef.assert($cond) } + } + } +} diff --git a/tests/run-macros/reflect-lambda/test_2.scala b/tests/run-macros/reflect-lambda/test_2.scala new file mode 100644 index 000000000000..bb712c81b477 --- /dev/null +++ b/tests/run-macros/reflect-lambda/test_2.scala @@ -0,0 +1,14 @@ +object Test { + import lib._ + + case class IntList(args: Int*) { + def exists(f: Int => Boolean): Boolean = args.exists(f) + } + + def main(args: Array[String]): Unit = { + assert(IntList(3, 5).exists(_ == 3)) + assert(IntList(3, 5).exists(5 == _)) + assert(IntList(3, 5).exists(x => x == 3)) + assert(IntList(3, 5).exists(x => 5 == x)) + } +} From 8fe1d7569798a95016dc85ed83e7bec5d05c5404 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 4 Jul 2019 17:35:48 +0200 Subject: [PATCH 3/7] Simplify reflect Printers with extractor for function literal --- .../src/scala/tasty/reflect/Printers.scala | 35 ++++++------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index 50dd64596f2d..de22bdaddf99 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -741,17 +741,6 @@ trait Printers printTree(body) } - case IsDefDef(ddef @ DefDef(name, targs, argss, _, rhsOpt)) if name.startsWith("$anonfun") => - // Decompile lambda definition - assert(targs.isEmpty) - val args :: Nil = argss - val Some(rhs) = rhsOpt - inParens { - printArgsDefs(args) - this += " => " - printTree(rhs) - } - case IsDefDef(ddef @ DefDef(name, targs, argss, tpt, rhs)) => printDefAnnotations(ddef) @@ -912,9 +901,13 @@ trait Printers case Inlined(_, bindings, expansion) => printFlatBlock(bindings, expansion) - case Closure(meth, tpt) => - // Printed in by it's DefDef - this + case Lambda(params, body) => + inParens { + printArgsDefs(params) + this += " => " + printTree(body) + } + case If(cond, thenp, elsep) => this += highlightKeyword("if ") @@ -1018,24 +1011,16 @@ trait Printers def printFlatBlock(stats: List[Statement], expr: Term)(implicit elideThis: Option[Symbol]): Buffer = { val (stats1, expr1) = flatBlock(stats, expr) - // Remove Lambda nodes, lambdas are printed by their definition val stats2 = stats1.filter { - case Closure(_, _) => false case IsTypeDef(tree) => !tree.symbol.annots.exists(_.symbol.owner.fullName == "scala.internal.Quoted$.quoteTypeTag") case _ => true } - val (stats3, expr3) = expr1 match { - case Closure(_, _) => - val init :+ last = stats2 - (init, last) - case _ => (stats2, expr1) - } - if (stats3.isEmpty) { - printTree(expr3) + if (stats2.isEmpty) { + printTree(expr1) } else { this += "{" indented { - printStats(stats3, expr3) + printStats(stats2, expr1) } this += lineBreak() += "}" } From 5292999c1fc95902d000c4e80d3d3e1ada3db7f9 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 4 Jul 2019 17:39:16 +0200 Subject: [PATCH 4/7] Remove obsolete docs --- library/src/scala/tasty/reflect/Core.scala | 3 --- library/src/scala/tasty/reflect/Kernel.scala | 3 --- 2 files changed, 6 deletions(-) diff --git a/library/src/scala/tasty/reflect/Core.scala b/library/src/scala/tasty/reflect/Core.scala index f2069832a541..6776c7f4c22b 100644 --- a/library/src/scala/tasty/reflect/Core.scala +++ b/library/src/scala/tasty/reflect/Core.scala @@ -208,9 +208,6 @@ trait Core { * closure(m) * } * - * While a function literal is usually a block with the two parts, - * in the Dotty compiler, the two parts may locate in a flattened - * block and may not be consecutive. */ type Closure = kernel.Closure diff --git a/library/src/scala/tasty/reflect/Kernel.scala b/library/src/scala/tasty/reflect/Kernel.scala index 33cd76f6f76e..9d17a3094f53 100644 --- a/library/src/scala/tasty/reflect/Kernel.scala +++ b/library/src/scala/tasty/reflect/Kernel.scala @@ -444,9 +444,6 @@ trait Kernel { * closure(m) * } * - * While a function literal is usually a block with the two parts, - * in the Dotty compiler, the two parts may locate in a flattened - * block and may not be consecutive. */ type Closure <: Term From 575f989536db5fc04831022833102a67bd892cfb Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 4 Jul 2019 21:39:10 +0200 Subject: [PATCH 5/7] Fix CI: avoid flattening of lambdas in reflect printers --- library/src/scala/tasty/reflect/Printers.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index de22bdaddf99..a99466bf6e6f 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -976,6 +976,8 @@ trait Printers def flatBlock(stats: List[Statement], expr: Term): (List[Statement], Term) = { val flatStats = List.newBuilder[Statement] def extractFlatStats(stat: Statement): Unit = stat match { + case Lambda(_, _) => // must come before `Block` + flatStats += stat case Block(stats1, expr1) => val it = stats1.iterator while (it.hasNext) @@ -990,6 +992,8 @@ trait Printers case stat => flatStats += stat } def extractFlatExpr(term: Term): Term = term match { + case Lambda(_, _) => // must come before `Block` + term case Block(stats1, expr1) => val it = stats1.iterator while (it.hasNext) From a147fbab71248228e9229c06397d7e5555f2c4fd Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 4 Jul 2019 22:40:07 +0200 Subject: [PATCH 6/7] Fix reflect printers: Lambda case should come before Block --- library/src/scala/tasty/reflect/Printers.scala | 15 +++++++-------- library/src/scala/tasty/reflect/TreeOps.scala | 3 +++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index a99466bf6e6f..a041f9d7fb5e 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -891,6 +891,13 @@ trait Printers this += " = " printTree(rhs) + case Lambda(params, body) => // must come before `Block` + inParens { + printArgsDefs(params) + this += " => " + printTree(body) + } + case Block(stats0, expr) => val stats = stats0.filter { case IsValDef(tree) => !tree.symbol.flags.is(Flags.Object) @@ -901,14 +908,6 @@ trait Printers case Inlined(_, bindings, expansion) => printFlatBlock(bindings, expansion) - case Lambda(params, body) => - inParens { - printArgsDefs(params) - this += " => " - printTree(body) - } - - case If(cond, thenp, elsep) => this += highlightKeyword("if ") inParens(printTree(cond)) diff --git a/library/src/scala/tasty/reflect/TreeOps.scala b/library/src/scala/tasty/reflect/TreeOps.scala index 1529d6f7b7be..1fce02ece91e 100644 --- a/library/src/scala/tasty/reflect/TreeOps.scala +++ b/library/src/scala/tasty/reflect/TreeOps.scala @@ -582,6 +582,9 @@ trait TreeOps extends Core { * closure(m) * } * + * @note Due to the encoding, in pattern matches the case for `Lambda` + * should come before the case for `Block` to avoid mishandling + * of `Lambda`. */ object Lambda { def unapply(tree: Tree)(implicit ctx: Context): Option[(List[ValDef], Term)] = tree match { From d93e10c7533690bfc3f5e427e572ede1f856ba4d Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Fri, 5 Jul 2019 00:05:06 +0200 Subject: [PATCH 7/7] Fix tests --- library/src/scala/tasty/reflect/Printers.scala | 1 + tests/run-macros/i5941/macro_1.scala | 8 +------- tests/run-macros/tasty-extractors-2.check | 4 ++-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index a041f9d7fb5e..6530eebc0bbf 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -1033,6 +1033,7 @@ trait Printers def printSeparator(next: Tree): Unit = { // Avoid accidental application of opening `{` on next line with a double break def rec(next: Tree): Unit = next match { + case Lambda(_, _) => this += lineBreak() case Block(stats, _) if stats.nonEmpty => this += doubleLineBreak() case Inlined(_, bindings, _) if bindings.nonEmpty => this += doubleLineBreak() case Select(qual, _) => rec(qual) diff --git a/tests/run-macros/i5941/macro_1.scala b/tests/run-macros/i5941/macro_1.scala index ff98000e709c..0df03c9534d1 100644 --- a/tests/run-macros/i5941/macro_1.scala +++ b/tests/run-macros/i5941/macro_1.scala @@ -40,13 +40,7 @@ object Lens { object Function { def unapply(t: Term): Option[(List[ValDef], Term)] = t match { - case Inlined( - None, Nil, - Block( - (ddef @ DefDef(_, Nil, params :: Nil, _, Some(body))) :: Nil, - Lambda(meth, _) - ) - ) if meth.symbol == ddef.symbol => Some((params, body)) + case Inlined(None, Nil, Lambda(params, body)) => Some((params, body)) case _ => None } } diff --git a/tests/run-macros/tasty-extractors-2.check b/tests/run-macros/tasty-extractors-2.check index f6c53839ddd8..e148497f1314 100644 --- a/tests/run-macros/tasty-extractors-2.check +++ b/tests/run-macros/tasty-extractors-2.check @@ -1,7 +1,7 @@ Inlined(None, Nil, Block(List(ValDef("x", Inferred(), Some(Literal(Constant(1))))), Assign(Ident("x"), Literal(Constant(2))))) Type.SymRef(IsClassDefSymbol(), Type.ThisType(Type.SymRef(IsPackageDefSymbol(), NoPrefix()))) -Inlined(None, Nil, Block(List(DefDef("$anonfun", Nil, List(List(ValDef("x", TypeIdent("Int"), None))), Inferred(), Some(Ident("x")))), Lambda(Ident("$anonfun"), None))) +Inlined(None, Nil, Block(List(DefDef("$anonfun", Nil, List(List(ValDef("x", TypeIdent("Int"), None))), Inferred(), Some(Ident("x")))), Closure(Ident("$anonfun"), None))) Type.AppliedType(Type.SymRef(IsClassDefSymbol(), Type.ThisType(Type.SymRef(IsPackageDefSymbol(), NoPrefix()))), List(Type.SymRef(IsClassDefSymbol(), Type.SymRef(IsPackageDefSymbol(), Type.ThisType(Type.SymRef(IsPackageDefSymbol(<>), NoPrefix())))), Type.SymRef(IsClassDefSymbol(), Type.SymRef(IsPackageDefSymbol(), Type.ThisType(Type.SymRef(IsPackageDefSymbol(<>), NoPrefix())))))) Inlined(None, Nil, Ident("???")) @@ -100,6 +100,6 @@ Type.SymRef(IsClassDefSymbol(), Type.ThisType(Type.SymRef(IsPackageD Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), ""), Nil)), Nil, None, List(TypeDef("X", TypeBoundsTree(Inferred(), Inferred())))), DefDef("f", Nil, List(List(ValDef("a", Refined(TypeIdent("Foo"), List(TypeDef("X", TypeIdent("Int")))), None))), TypeSelect(Ident("a"), "X"), Some(Ident("???")))), Literal(Constant(())))) Type.SymRef(IsClassDefSymbol(), Type.ThisType(Type.SymRef(IsPackageDefSymbol(), NoPrefix()))) -Inlined(None, Nil, Block(List(ValDef("lambda", Applied(Inferred(), List(TypeIdent("Int"), TypeIdent("Int"))), Some(Block(List(DefDef("$anonfun", Nil, List(List(ValDef("x", Inferred(), None))), Inferred(), Some(Ident("x")))), Lambda(Ident("$anonfun"), None))))), Literal(Constant(())))) +Inlined(None, Nil, Block(List(ValDef("lambda", Applied(Inferred(), List(TypeIdent("Int"), TypeIdent("Int"))), Some(Block(List(DefDef("$anonfun", Nil, List(List(ValDef("x", Inferred(), None))), Inferred(), Some(Ident("x")))), Closure(Ident("$anonfun"), None))))), Literal(Constant(())))) Type.SymRef(IsClassDefSymbol(), Type.ThisType(Type.SymRef(IsPackageDefSymbol(), NoPrefix())))