From 43a267325c5f6af1c48597d0ff5ba73f6f08115a Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 17 Nov 2021 09:00:16 +0100 Subject: [PATCH] Add regression test ConstructExpr and DestructExpr are used to construct and destruct case classes into and from tuples containing the expressions of their elements. --- .../contruct-desturct/ConstructExpr.scala | 45 ++++++++++++++++++ .../contruct-desturct/DestructExpr.scala | 47 +++++++++++++++++++ tests/pos-macros/contruct-desturct/Test.scala | 7 +++ 3 files changed, 99 insertions(+) create mode 100644 tests/pos-macros/contruct-desturct/ConstructExpr.scala create mode 100644 tests/pos-macros/contruct-desturct/DestructExpr.scala create mode 100644 tests/pos-macros/contruct-desturct/Test.scala diff --git a/tests/pos-macros/contruct-desturct/ConstructExpr.scala b/tests/pos-macros/contruct-desturct/ConstructExpr.scala new file mode 100644 index 000000000000..6a2a6f40f0c5 --- /dev/null +++ b/tests/pos-macros/contruct-desturct/ConstructExpr.scala @@ -0,0 +1,45 @@ +package scala.quoted +package util + +trait ConstructExpr[T] { + + type Elems <: Tuple + + def from(x: Elems)(using Quotes): Expr[T] + // def from(x: Tuple.Map[Elems, Expr])(using Quotes): Expr[T] // alternative + +} + +object ConstructExpr { + + def apply[T](using ce: ConstructExpr[T]): ce.type = ce + + /** Default implementation of `ConstructExpr[Tuple1[T]]` */ + given EmptyTupleConstructExpr[T: Type]: ConstructExpr[EmptyTuple] with { + type Elems = EmptyTuple + def from(x: Elems)(using Quotes): Expr[EmptyTuple] = + '{ EmptyTuple } + } + + /** Default implementation of `ConstructExpr[Tuple1[T]]` */ + given Tuple1ConstructExpr[T: Type]: ConstructExpr[Tuple1[T]] with { + type Elems = Tuple1[Expr[T]] + def from(x: Elems)(using Quotes): Expr[Tuple1[T]] = + '{ Tuple1[T](${x._1}) } + } + + /** Default implementation of `ConstructExpr[Tuple2[T1, T2]]` */ + given Tuple2ConstructExpr[T1: Type, T2: Type]: ConstructExpr[Tuple2[T1, T2]] with { + type Elems = (Expr[T1], Expr[T2]) + def from(x: Elems)(using Quotes): Expr[Tuple2[T1, T2]] = + '{ Tuple2[T1, T2](${x._1}, ${x._2}) } + } + + /** Default implementation of `ConstructExpr[Tuple3[T1, T2, T3]]` */ + given Tuple3ConstructExpr[T1: Type, T2: Type, T3: Type]: ConstructExpr[Tuple3[T1, T2, T3]] with { + type Elems = (Expr[T1], Expr[T2], Expr[T3]) + def from(x: Elems)(using Quotes): Expr[Tuple3[T1, T2, T3]] = + '{ Tuple3[T1, T2, T3](${x._1}, ${x._2}, ${x._3}) } + } + +} diff --git a/tests/pos-macros/contruct-desturct/DestructExpr.scala b/tests/pos-macros/contruct-desturct/DestructExpr.scala new file mode 100644 index 000000000000..b54be5e1116a --- /dev/null +++ b/tests/pos-macros/contruct-desturct/DestructExpr.scala @@ -0,0 +1,47 @@ +package scala.quoted +package util + +trait DestructExpr[T] { + + type Elems <: Tuple + + def unapply(x: Expr[T])(using Quotes): Option[Elems] + // def unapply(x: Expr[T])(using Quotes): Option[Tuple.Map[Elems, Expr]] // alternative + +} + +/** Default given instances of `DestructExpr` */ +object DestructExpr { + + def unapply[T](x: Expr[T])(using de: DestructExpr[T])(using Quotes): Option[de.Elems] = + de.unapply(x) + + + /** Default implementation of `DestructExpr[Tuple1[...]]` + * - Transform `'{Tuple1(x1)}` into `Some(Tuple1('{x1}))` + * - Otherwise returns `None` + */ + given DestructTuple1[T1](using Type[T1]): DestructExpr[Tuple1[T1]] with { + type Elems = Tuple1[Expr[T1]] + def unapply(x: Expr[Tuple1[T1]])(using Quotes) = x match { + case '{ new Tuple1[T1]($y) } => Some(Tuple1(y)) + case '{ Tuple1[T1]($y) } => Some(Tuple1(y)) + case _ => None + } + } + + /** Default implementation of `DestructExpr[Tuple2[...]]` + * - Transform `'{Tuple2(x1, x2)}` into `Some(Tuple2('{x1}, '{x2}))` + * - Otherwise returns `None` + */ + given DestructTuple2[T1, T2](using Type[T1], Type[T2]): DestructExpr[Tuple2[T1, T2]] with { + type Elems = (Expr[T1], Expr[T2]) + def unapply(x: Expr[Tuple2[T1, T2]])(using Quotes) = x match { + case '{ new Tuple2[T1, T2]($y1, $y2) } => Some(Tuple2(y1, y2)) + case '{ Tuple2[T1, T2]($y1, $y2) } => Some(Tuple2(y1, y2)) + case '{ ($y1: T1) -> ($y2: T2) } => Some(Tuple2(y1, y2)) + case _ => None + } + } + +} diff --git a/tests/pos-macros/contruct-desturct/Test.scala b/tests/pos-macros/contruct-desturct/Test.scala new file mode 100644 index 000000000000..a4d159ed7d35 --- /dev/null +++ b/tests/pos-macros/contruct-desturct/Test.scala @@ -0,0 +1,7 @@ +import scala.quoted.* +import scala.quoted.util.* + +def test(using Quotes) = + '{ Tuple2(1, 2) } match + case DestructExpr((a, b)) => + ConstructExpr[(Int, Int)].from((a, b))