Skip to content

Commit 8a51a38

Browse files
Add toExprOfTuple method for tuples
1 parent 051f6a6 commit 8a51a38

File tree

5 files changed

+46
-1
lines changed

5 files changed

+46
-1
lines changed

compiler/test/dotc/pos-test-pickling.blacklist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ i7087.scala
2525

2626
# Opaque type
2727
i5720.scala
28+
29+
# Tuples
30+
toexproftuple.scala

library/src-bootstrapped/scala/quoted/package.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ package object quoted {
9595
'{ Tuple.fromIArray(IArray(${seq.toExprOfSeq}: _*)) }
9696
}
9797
}
98-
}
9998

99+
/** Given a tuple of the form `(Expr[A1], ..., Expr[An])`, outputs a tuple `Expr[(A1, ..., An)]`. */
100+
def (tup: T) toExprOfTuple[T <: Tuple: Tuple.IsMappedBy[Expr]: Type] given (ctx: QuoteContext): Expr[Tuple.InverseMap[T, Expr]] = {
101+
import ctx.tasty._
102+
tup.asInstanceOf[Product].productIterator.toSeq.asInstanceOf[Seq[Expr[_]]].toExprOfTuple
103+
.cast[Tuple.InverseMap[T, Expr]]
104+
}
105+
}
100106
}

library/src/scala/Tuple.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,23 @@ object Tuple {
103103
case _ => Tuple
104104
}
105105

106+
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
107+
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
108+
case F[x] *: t => x *: InverseMap[t, F]
109+
case Unit => Unit
110+
}
111+
112+
/** Implicit evidence. IsMappedBy[F][X] is present in the implicit scope iff
113+
* X is a tuple for which each element's type is constructed via `F`. E.g.
114+
* (F[A1], ..., F[An]), but not `(F[A1], B2, ..., F[An])` where B2 does not
115+
* have the shape of `F[A]`.
116+
*/
117+
type IsMappedBy[F[_]] = [X <: Tuple] =>> X <:< IsMappedByImpl[X, F]
118+
type IsMappedByImpl[X <: Tuple, F[_]] <: Tuple = X match {
119+
case F[x] *: t => F[x] *: IsMappedByImpl[t, F]
120+
case Unit => Unit
121+
}
122+
106123
/** Convert an array into a tuple of unknown arity and types */
107124
def fromArray[T](xs: Array[T]): Tuple = {
108125
val xs2 = xs match {

tests/neg/toexproftuple.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted._, scala.deriving._
2+
import given scala.quoted._
3+
4+
inline def mcr: Any = ${mcrImpl}
5+
def mcrImpl given (ctx: QuoteContext): Expr[Any] = {
6+
val tpl: (Expr[1], Expr[2], Expr[3]) = ('{1}, '{2}, '{3})
7+
'{val res: (1, 3, 3) = ${tpl.toExprOfTuple}; res} // error
8+
9+
val tpl2: (Expr[1], 2, Expr[3]) = ('{1}, 2, '{3})
10+
'{val res = ${tpl2.toExprOfTuple}; res} // error
11+
}

tests/pos/toexproftuple.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted._, scala.deriving._
2+
import given scala.quoted._
3+
4+
inline def mcr: Any = ${mcrImpl}
5+
def mcrImpl given (ctx: QuoteContext): Expr[Any] = {
6+
val tpl: (Expr[1], Expr[2], Expr[3]) = ('{1}, '{2}, '{3})
7+
'{val res: (1, 2, 3) = ${tpl.toExprOfTuple}; res}
8+
}

0 commit comments

Comments
 (0)