From 7e4fe17ae79061938a93b66aa1b296bd785b0bf8 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 9 Jan 2023 09:32:33 +0100 Subject: [PATCH] `Expr.betaReduce` support for polymorphic function Fixes #15968 --- .../scala/quoted/runtime/impl/QuotesImpl.scala | 5 ++++- tests/run-macros/i15968/Macro_1.scala | 15 +++++++++++++++ tests/run-macros/i15968/Test_2.scala | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/run-macros/i15968/Macro_1.scala create mode 100644 tests/run-macros/i15968/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 7cbf05871e08..277cfd9f8cfb 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -362,11 +362,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object Term extends TermModule: def betaReduce(tree: Term): Option[Term] = tree match - // TODO support TypeApply. Would fix #15968. case app @ tpd.Apply(tpd.Select(fn, nme.apply), args) if dotc.core.Symbols.defn.isFunctionType(fn.tpe) => val app1 = dotc.transform.BetaReduce(app, fn, List(args)) if app1 eq app then None else Some(app1.withSpan(tree.span)) + case app @ tpd.Apply(tpd.TypeApply(tpd.Select(fn, nme.apply), targs), args) if fn.tpe.typeSymbol eq dotc.core.Symbols.defn.PolyFunctionClass => + val app1 = dotc.transform.BetaReduce(app, fn, List(targs, app.args)) + if app1 eq app then None + else Some(app1.withSpan(tree.span)) case tpd.Block(Nil, expr) => for e <- betaReduce(expr) yield tpd.cpy.Block(tree)(Nil, e) case tpd.Inlined(_, Nil, expr) => diff --git a/tests/run-macros/i15968/Macro_1.scala b/tests/run-macros/i15968/Macro_1.scala new file mode 100644 index 000000000000..ea2728840d6e --- /dev/null +++ b/tests/run-macros/i15968/Macro_1.scala @@ -0,0 +1,15 @@ +import scala.quoted.* + +inline def macroPolyFun[A](inline arg: A, inline f: [Z] => Z => String): String = + ${ macroPolyFunImpl[A]('arg, 'f) } + +private def macroPolyFunImpl[A: Type](arg: Expr[A], f: Expr[[Z] => Z => String])(using Quotes): Expr[String] = + Expr(Expr.betaReduce('{ $f($arg) }).show) + + +inline def macroFun[A](inline arg: A, inline f: A => String): String = + ${ macroFunImpl[A]('arg, 'f) } + +private def macroFunImpl[A: Type](arg: Expr[A], f: Expr[A => String])(using Quotes): Expr[String] = + Expr(Expr.betaReduce('{ $f($arg) }).show) + diff --git a/tests/run-macros/i15968/Test_2.scala b/tests/run-macros/i15968/Test_2.scala new file mode 100644 index 000000000000..6c6826f96b34 --- /dev/null +++ b/tests/run-macros/i15968/Test_2.scala @@ -0,0 +1,3 @@ +@main def Test: Unit = + println(macroPolyFun("foo", [Z] => (arg: Z) => arg.toString)) + println(macroFun("foo", arg => arg.toString))