Skip to content

Commit 0e1c29d

Browse files
authored
Merge pull request #7299 from dotty-staging/remove-asFunction-implicit-class
Replace AsFunction implicit class with Expr.reduce
2 parents 5bcb1ce + 1979749 commit 0e1c29d

File tree

26 files changed

+119
-111
lines changed

26 files changed

+119
-111
lines changed

docs/docs/reference/metaprogramming/macros.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,24 +135,20 @@ expressiveness.
135135

136136
### From `Expr`s to Functions and Back
137137

138-
The `Expr` companion object contains an implicit `AsFunction` conversion that turns a tree
138+
The `Expr` companion object contains a `betaReduce` conversion that turns a tree
139139
describing a function into a function mapping trees to trees.
140140
```scala
141141
object Expr {
142142
...
143-
implicit class AsFunction[...](...) { ... }
143+
def betaReduce[...](...)(...): ... = ...
144144
}
145145
```
146-
This decorator gives `Expr` the `apply` operation of an applicative functor, where `Expr`s
147-
over function types can be applied to `Expr` arguments. The definition
148-
of `AsFunction(f).apply(x)` is assumed to be functionally the same as
146+
The definition of `Expr.betaReduce(f)(x)` is assumed to be functionally the same as
149147
`'{($f)($x)}`, however it should optimize this call by returning the
150148
result of beta-reducing `f(x)` if `f` is a known lambda expression.
151-
152-
The `AsFunction` decorator distributes applications of `Expr` over function
153-
arrows:
149+
`Expr.betaReduce` distributes applications of `Expr` over function arrows:
154150
```scala
155-
AsFunction(_).apply: Expr[S => T] => (Expr[S] => Expr[T])
151+
Expr.betaReduce(_): Expr[(T1, ..., Tn) => R] => ((Expr[T1], ..., Expr[Tn]) => Expr[R])
156152
```
157153
Its dual, let’s call it `reflect`, can be defined as follows:
158154
```scala

library/src/scala/quoted/Expr.scala

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,31 @@ package quoted {
2828
/** Converts a tuple `(T1, ..., Tn)` to `(Expr[T1], ..., Expr[Tn])` */
2929
type TupleOfExpr[Tup <: Tuple] = Tuple.Map[Tup, [X] =>> (given QuoteContext) => Expr[X]]
3030

31-
implicit class AsFunction[F, Args <: Tuple, R](f: Expr[F])(given tf: TupledFunction[F, Args => R], qctx: QuoteContext) {
32-
/** Beta-reduces the function appication. Generates the an expression only containing the body of the function */
33-
def apply[G](given tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]]): G = {
34-
import qctx.tasty._
35-
tg.untupled(args => qctx.tasty.internal.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
36-
}
31+
/** `Expr.betaReduce(f)(x1, ..., xn)` is functionally the same as `'{($f)($x1, ..., $xn)}`, however it optimizes this call
32+
* by returning the result of beta-reducing `f(x1, ..., xn)` if `f` is a known lambda expression.
33+
*
34+
* `Expr.betaReduce` distributes applications of `Expr` over function arrows
35+
* ```scala
36+
* Expr.betaReduce(_): Expr[(T1, ..., Tn) => R] => ((Expr[T1], ..., Expr[Tn]) => Expr[R])
37+
* ```
38+
*/
39+
def betaReduce[F, Args <: Tuple, R, G](f: Expr[F])(given tf: TupledFunction[F, Args => R], tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]], qctx: QuoteContext): G = {
40+
import qctx.tasty._
41+
tg.untupled(args => qctx.tasty.internal.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
3742
}
3843

39-
implicit class AsContextualFunction[F, Args <: Tuple, R](f: Expr[F])(given tf: TupledFunction[F, (given Args) => R], qctx: QuoteContext) {
40-
/** Beta-reduces the function appication. Generates the an expression only containing the body of the function */
41-
def apply[G](given tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]]): G = {
42-
import qctx.tasty._
43-
tg.untupled(args => qctx.tasty.internal.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
44-
}
44+
/** `Expr.betaReduceGiven(f)(x1, ..., xn)` is functionally the same as `'{($f)(given $x1, ..., $xn)}`, however it optimizes this call
45+
* by returning the result of beta-reducing `f(given x1, ..., xn)` if `f` is a known lambda expression.
46+
*
47+
* `Expr.betaReduceGiven` distributes applications of `Expr` over function arrows
48+
* ```scala
49+
* Expr.betaReduceGiven(_): Expr[(given T1, ..., Tn) => R] => ((Expr[T1], ..., Expr[Tn]) => Expr[R])
50+
* ```
51+
* Note: The
52+
*/
53+
def betaReduceGiven[F, Args <: Tuple, R, G](f: Expr[F])(given tf: TupledFunction[F, (given Args) => R], tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]], qctx: QuoteContext): G = {
54+
import qctx.tasty._
55+
tg.untupled(args => qctx.tasty.internal.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
4556
}
4657

4758
/** Returns a null expresssion equivalent to `'{null}` */

tests/pos/i6783.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.quoted._
22

3-
def testImpl(f: Expr[(Int, Int) => Int])(given QuoteContext): Expr[Int] = f('{1}, '{2})
3+
def testImpl(f: Expr[(Int, Int) => Int])(given QuoteContext): Expr[Int] = Expr.betaReduce(f)('{1}, '{2})
44

55
inline def test(f: (Int, Int) => Int) = ${
66
testImpl('f)

tests/run-macros/gestalt-optional-staging/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ object Optional {
2424
// FIXME fix issue #5097 and enable private
2525
/*private*/ def mapImpl[A >: Null : Type, B >: Null : Type](opt: Expr[Optional[A]], f: Expr[A => B])(given QuoteContext): Expr[Optional[B]] = '{
2626
if ($opt.isEmpty) new Optional(null)
27-
else new Optional(${f('{$opt.value})})
27+
else new Optional(${Expr.betaReduce(f)('{$opt.value})})
2828
}
2929

3030
}

tests/run-macros/i4734/Macro_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ object Macros {
1313
while (i < size) {
1414
${
1515
for (j <- new UnrolledRange(0, unrollSize)) '{
16-
val index = i + ${j}
16+
val index = i + $j
1717
val element = ($seq)(index)
18-
${ f('element) } // or `($f)(element)` if `f` should not be inlined
18+
${ Expr.betaReduce(f)('element) } // or `($f)(element)` if `f` should not be inlined
1919
}
2020
}
2121
i += ${unrollSize}

tests/run-macros/i4735/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object Macro {
1717
${
1818
for (j <- new UnrolledRange(0, unrollSize)) '{
1919
val element = ($seq)(i + ${j})
20-
${f('element)} // or `($f)(element)` if `f` should not be inlined
20+
${Expr.betaReduce(f)('element)} // or `($f)(element)` if `f` should not be inlined
2121
}
2222
}
2323
i += ${unrollSize}

tests/run-macros/i7008/macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ def mcrProxy(expr: Expr[Boolean])(given QuoteContext): Expr[Unit] = {
1515
def mcrImpl[T](func: Expr[Seq[Box[T]] => Unit], expr: Expr[T])(given ctx: QuoteContext, tt: Type[T]): Expr[Unit] = {
1616
import ctx.tasty._
1717
val arg = Expr.ofSeq(Seq('{(Box($expr))}))
18-
func(arg)
18+
Expr.betaReduce(func)(arg)
1919
}

tests/run-macros/quote-inline-function/quoted_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ object Macros {
1212
var i = $start
1313
val j = $end
1414
while (i < j) {
15-
${f.apply('i)}
15+
${Expr.betaReduce(f)('i)}
1616
i += 1
1717
}
1818
while {
19-
${f.apply('i)}
19+
${Expr.betaReduce(f)('i)}
2020
i += 1
2121
i < j
2222
} do ()

tests/run-macros/quote-matcher-symantics-2/quoted_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ object StringNum extends Symantics[String] {
7272
def value(x: Int)(given QuoteContext): Expr[String] = Expr(x.toString)
7373
def plus(x: Expr[String], y: Expr[String])(given QuoteContext): Expr[String] = '{ s"${$x} + ${$y}" } // '{ x + " + " + y }
7474
def times(x: Expr[String], y: Expr[String])(given QuoteContext): Expr[String] = '{ s"${$x} * ${$y}" }
75-
def app(f: Expr[String => String], x: Expr[String])(given QuoteContext): Expr[String] = f(x) // functions are beta reduced
75+
def app(f: Expr[String => String], x: Expr[String])(given QuoteContext): Expr[String] = Expr.betaReduce(f)(x)
7676
def lam(body: Expr[String] => Expr[String])(given QuoteContext): Expr[String => String] = '{ (x: String) => ${body('x)} }
7777
}
7878

0 commit comments

Comments
 (0)