Skip to content

Use TupledFunction for Expr.FunctionBetaReduction #6618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ class Definitions {
}

def tupleTypes(tp: Type, bound: Int = Int.MaxValue)(implicit ctx: Context): Option[List[Type]] = {
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp match {
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp.normalized match {
case _ if bound < 0 => Some(acc.reverse)
case tp: AppliedType if defn.PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
case tp: AppliedType if defn.isTupleClass(tp.tycon.classSymbol) => Some(acc.reverse ::: tp.args)
Expand Down
21 changes: 5 additions & 16 deletions compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {

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

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

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

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

private def transformTupleToArray(tree: tpd.Apply)(implicit ctx: Context): Tree = {
val Apply(_, tup :: Nil) = tree
tupleTypes(tup.tpe.widen, MaxTupleArity) match {
defn.tupleTypes(tup.tpe.widen, MaxTupleArity) match {
case Some(tpes) =>
val size = tpes.size
if (size == 0) {
Expand Down Expand Up @@ -222,17 +222,6 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
}
}

private def tupleTypes(tp: Type, bound: Int = Int.MaxValue)(implicit ctx: Context): Option[List[Type]] = {
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp match {
case _ if bound < 0 => Some(acc.reverse)
case tp: AppliedType if defn.PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
case tp: AppliedType if defn.isTupleClass(tp.tycon.classSymbol) => Some(acc.reverse ::: tp.args)
case tp if tp.classSymbol == defn.UnitClass => Some(acc.reverse)
case _ => None
}
rec(tp.stripTypeVar, Nil, bound)
}

private def tupleSelectors(tup: Tree, size: Int)(implicit ctx: Context): List[Tree] =
(0 until size).map(i => tup.select(nme.selectorName(i))).toList

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ trait Implicits { self: Typer =>
// TupledFunction[?, (...) => R]
tupled.dropDependentRefinement.dealias.argInfos match {
case tupledArgs :: funRet :: Nil =>
defn.tupleTypes(tupledArgs) match {
defn.tupleTypes(tupledArgs.dealias) match {
case Some(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) =>
// TupledFunction[?, ((...funArgs...)) => funRet]
funArgs.size
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/reference/metaprogramming/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,24 +135,24 @@ expressiveness.

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

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

The `AsFunction1` decorator distributes applications of `Expr` over function
The `AsFunction` decorator distributes applications of `Expr` over function
arrows:
```scala
AsFunction1(_).apply: Expr[S => T] => (Expr[S] => Expr[T])
AsFunction(_).apply: Expr[S => T] => (Expr[S] => Expr[T])
```
Its dual, let’s call it `reflect`, can be defined as follows:
```scala
Expand Down
6 changes: 6 additions & 0 deletions library/src-3.x/scala/Tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ object Tuple {
case x *: xs => S[Size[xs]]
}

/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
type Map[Tup <: Tuple, F[_]] <: Tuple = Tup match {
case Unit => Unit
case h *: t => F[h] *: Map[t, F]
}

/** Convert an array into a tuple of unknown arity and types */
def fromArray[T](xs: Array[T]): Tuple = {
val xs2 = xs match {
Expand Down
Loading