Skip to content

Commit 3c591ed

Browse files
Merge pull request #6618 from dotty-staging/improve-quoted-expr-FunctionBetaReduction
Use TupledFunction for Expr.FunctionBetaReduction
2 parents e2818f0 + fb54ac0 commit 3c591ed

File tree

6 files changed

+27
-293
lines changed

6 files changed

+27
-293
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ class Definitions {
12601260
}
12611261

12621262
def tupleTypes(tp: Type, bound: Int = Int.MaxValue)(implicit ctx: Context): Option[List[Type]] = {
1263-
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp match {
1263+
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp.normalized match {
12641264
case _ if bound < 0 => Some(acc.reverse)
12651265
case tp: AppliedType if defn.PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
12661266
case tp: AppliedType if defn.isTupleClass(tp.tycon.classSymbol) => Some(acc.reverse ::: tp.args)

compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
3636

3737
private def transformTupleCons(tree: tpd.Apply)(implicit ctx: Context): Tree = {
3838
val head :: tail :: Nil = tree.args
39-
tupleTypes(tree.tpe) match {
39+
defn.tupleTypes(tree.tpe) match {
4040
case Some(tpes) =>
4141
// Generate a the tuple directly with TupleN+1.apply
4242
val size = tpes.size
@@ -64,7 +64,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
6464

6565
private def transformTupleTail(tree: tpd.Apply)(implicit ctx: Context): Tree = {
6666
val Apply(TypeApply(_, tpt :: Nil), tup :: Nil) = tree
67-
tupleTypes(tpt.tpe, MaxTupleArity + 1) match {
67+
defn.tupleTypes(tpt.tpe, MaxTupleArity + 1) match {
6868
case Some(tpes) =>
6969
// Generate a the tuple directly with TupleN-1.apply
7070
val size = tpes.size
@@ -111,7 +111,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
111111
private def transformTupleConcat(tree: tpd.Apply)(implicit ctx: Context): Tree = {
112112
val Apply(TypeApply(_, selfTp :: thatTp :: Nil), self :: that :: Nil) = tree
113113

114-
(tupleTypes(selfTp.tpe), tupleTypes(that.tpe.widenTermRefExpr)) match {
114+
(defn.tupleTypes(selfTp.tpe), defn.tupleTypes(that.tpe.widenTermRefExpr)) match {
115115
case (Some(tpes1), Some(tpes2)) =>
116116
// Generate a the tuple directly with TupleN+M.apply
117117
val n = tpes1.size
@@ -146,7 +146,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
146146

147147
private def transformTupleApply(tree: tpd.Apply)(implicit ctx: Context): Tree = {
148148
val Apply(TypeApply(_, tpt :: nTpt :: Nil), tup :: nTree :: Nil) = tree
149-
(tupleTypes(tpt.tpe), nTpt.tpe) match {
149+
(defn.tupleTypes(tpt.tpe), nTpt.tpe) match {
150150
case (Some(tpes), nTpe: ConstantType) =>
151151
// Get the element directly with TupleM._n+1 or TupleXXL.productElement(n)
152152
val size = tpes.size
@@ -173,7 +173,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
173173

174174
private def transformTupleToArray(tree: tpd.Apply)(implicit ctx: Context): Tree = {
175175
val Apply(_, tup :: Nil) = tree
176-
tupleTypes(tup.tpe.widen, MaxTupleArity) match {
176+
defn.tupleTypes(tup.tpe.widen, MaxTupleArity) match {
177177
case Some(tpes) =>
178178
val size = tpes.size
179179
if (size == 0) {
@@ -222,17 +222,6 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
222222
}
223223
}
224224

225-
private def tupleTypes(tp: Type, bound: Int = Int.MaxValue)(implicit ctx: Context): Option[List[Type]] = {
226-
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp match {
227-
case _ if bound < 0 => Some(acc.reverse)
228-
case tp: AppliedType if defn.PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
229-
case tp: AppliedType if defn.isTupleClass(tp.tycon.classSymbol) => Some(acc.reverse ::: tp.args)
230-
case tp if tp.classSymbol == defn.UnitClass => Some(acc.reverse)
231-
case _ => None
232-
}
233-
rec(tp.stripTypeVar, Nil, bound)
234-
}
235-
236225
private def tupleSelectors(tup: Tree, size: Int)(implicit ctx: Context): List[Tree] =
237226
(0 until size).map(i => tup.select(nme.selectorName(i))).toList
238227

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ trait Implicits { self: Typer =>
720720
// TupledFunction[?, (...) => R]
721721
tupled.dropDependentRefinement.dealias.argInfos match {
722722
case tupledArgs :: funRet :: Nil =>
723-
defn.tupleTypes(tupledArgs) match {
723+
defn.tupleTypes(tupledArgs.dealias) match {
724724
case Some(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) =>
725725
// TupledFunction[?, ((...funArgs...)) => funRet]
726726
funArgs.size

docs/docs/reference/metaprogramming/macros.md

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

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

138-
The `Expr` companion object contains an implicit `AsFunctionN` (for 0 <= N < 23) conversion that turns a tree
138+
The `Expr` companion object contains an implicit `AsFunction` conversion that turns a tree
139139
describing a function into a function mapping trees to trees.
140140
```scala
141141
object Expr {
142142
...
143-
implied AsFunction1[T, U] for Conversion[Expr[T => U], Expr[T] => Expr[U]] ...
143+
implicit class AsFunction[...](...) { ... }
144144
}
145145
```
146146
This decorator gives `Expr` the `apply` operation of an applicative functor, where `Expr`s
147147
over function types can be applied to `Expr` arguments. The definition
148-
of `AsFunction1(f).apply(x)` is assumed to be functionally the same as
148+
of `AsFunction(f).apply(x)` is assumed to be functionally the same as
149149
`'{($f)($x)}`, however it should optimize this call by returning the
150150
result of beta-reducing `f(x)` if `f` is a known lambda expression.
151151

152-
The `AsFunction1` decorator distributes applications of `Expr` over function
152+
The `AsFunction` decorator distributes applications of `Expr` over function
153153
arrows:
154154
```scala
155-
AsFunction1(_).apply: Expr[S => T] => (Expr[S] => Expr[T])
155+
AsFunction(_).apply: Expr[S => T] => (Expr[S] => Expr[T])
156156
```
157157
Its dual, let’s call it `reflect`, can be defined as follows:
158158
```scala

library/src-3.x/scala/Tuple.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ object Tuple {
6464
case x *: xs => S[Size[xs]]
6565
}
6666

67+
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
68+
type Map[Tup <: Tuple, F[_]] <: Tuple = Tup match {
69+
case Unit => Unit
70+
case h *: t => F[h] *: Map[t, F]
71+
}
72+
6773
/** Convert an array into a tuple of unknown arity and types */
6874
def fromArray[T](xs: Array[T]): Tuple = {
6975
val xs2 = xs match {

0 commit comments

Comments
 (0)