From 426a3d122d2c7c51ad5ef813ef0df0c4fb4afa58 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 25 Apr 2022 14:20:50 +0200 Subject: [PATCH 1/2] Fix derivation macro example Issue found in https://github.com/lampepfl/dotty/issues/13926#issuecomment-1084919198 Tested in tests/run-macros/i8007/Macro_3.scala (already up to date). --- docs/_docs/reference/contextual/derivation-macro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_docs/reference/contextual/derivation-macro.md b/docs/_docs/reference/contextual/derivation-macro.md index 5ff0007268dd..25b9475c7e80 100644 --- a/docs/_docs/reference/contextual/derivation-macro.md +++ b/docs/_docs/reference/contextual/derivation-macro.md @@ -49,7 +49,7 @@ given derived[T: Type](using Quotes): Expr[Eq[T]] = ev match case '{ $m: Mirror.ProductOf[T] { type MirroredElemTypes = elementTypes }} => val elemInstances = summonAll[elementTypes] - val eqProductBody: (Expr[T], Expr[T]) => Expr[Boolean] = (x, y) => + def eqProductBody(Expr[T], Expr[T])(using Quotes): Expr[Boolean] = (x, y) => elemInstances.zipWithIndex.foldLeft(Expr(true: Boolean)) { case (acc, (elem, index)) => val e1 = '{$x.asInstanceOf[Product].productElement(${Expr(index)})} From a218602b7e579b7499fbe5a9bb7ff281f7ec2ff7 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 25 Apr 2022 14:36:18 +0200 Subject: [PATCH 2/2] Avoid unchecked Expr casts --- .../reference/contextual/derivation-macro.md | 19 ++++++++++--------- tests/run-macros/i8007/Macro_3.scala | 16 ++++++++-------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/_docs/reference/contextual/derivation-macro.md b/docs/_docs/reference/contextual/derivation-macro.md index 25b9475c7e80..e404e2592000 100644 --- a/docs/_docs/reference/contextual/derivation-macro.md +++ b/docs/_docs/reference/contextual/derivation-macro.md @@ -49,15 +49,16 @@ given derived[T: Type](using Quotes): Expr[Eq[T]] = ev match case '{ $m: Mirror.ProductOf[T] { type MirroredElemTypes = elementTypes }} => val elemInstances = summonAll[elementTypes] - def eqProductBody(Expr[T], Expr[T])(using Quotes): Expr[Boolean] = (x, y) => - elemInstances.zipWithIndex.foldLeft(Expr(true: Boolean)) { - case (acc, (elem, index)) => - val e1 = '{$x.asInstanceOf[Product].productElement(${Expr(index)})} - val e2 = '{$y.asInstanceOf[Product].productElement(${Expr(index)})} - '{ $acc && $elem.asInstanceOf[Eq[Any]].eqv($e1, $e2) } - } - - '{ eqProduct((x: T, y: T) => ${eqProductBody('x, 'y)}) } + def eqProductBody(x: Expr[Product], y: Expr[Product])(using Quotes): Expr[Boolean] = { + elemInstances.zipWithIndex.foldLeft(Expr(true)) { + case (acc, ('{ $elem: Eq[t] }, index)) => + val indexExpr = Expr(index) + val e1 = '{ $x.productElement($indexExpr).asInstanceOf[t] } + val e2 = '{ $y.productElement($indexExpr).asInstanceOf[t] } + '{ $acc && $elem.eqv($e1, $e2) } + } + } + '{ eqProduct((x: T, y: T) => ${eqProductBody('x.asExprOf[Product], 'y.asExprOf[Product])}) } // case for Mirror.ProductOf[T] // ... diff --git a/tests/run-macros/i8007/Macro_3.scala b/tests/run-macros/i8007/Macro_3.scala index a0e52e93b618..7f429708c233 100644 --- a/tests/run-macros/i8007/Macro_3.scala +++ b/tests/run-macros/i8007/Macro_3.scala @@ -40,17 +40,17 @@ object Eq { ev match { case '{ $m: Mirror.ProductOf[T] { type MirroredElemTypes = elementTypes }} => val elemInstances = summonAll[elementTypes] - def eqProductBody(x: Expr[T], y: Expr[T])(using Quotes): Expr[Boolean] = { - elemInstances.zipWithIndex.foldLeft(Expr(true: Boolean)) { - case (acc, (elem, index)) => - val e1 = '{$x.asInstanceOf[Product].productElement(${Expr(index)})} - val e2 = '{$y.asInstanceOf[Product].productElement(${Expr(index)})} - - '{ $acc && $elem.asInstanceOf[Eq[Any]].eqv($e1, $e2) } + def eqProductBody(x: Expr[Product], y: Expr[Product])(using Quotes): Expr[Boolean] = { + elemInstances.zipWithIndex.foldLeft(Expr(true)) { + case (acc, ('{ $elem: Eq[t]}, index)) => + val indexExpr = Expr(index) + val e1 = '{ $x.productElement($indexExpr).asInstanceOf[t] } + val e2 = '{ $y.productElement($indexExpr).asInstanceOf[t] } + '{ $acc && $elem.eqv($e1, $e2) } } } '{ - eqProduct((x: T, y: T) => ${eqProductBody('x, 'y)}) + eqProduct((x: T, y: T) => ${eqProductBody('x.asExprOf[Product], 'y.asExprOf[Product])}) } case '{ $m: Mirror.SumOf[T] { type MirroredElemTypes = elementTypes }} =>