diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 2b534dac7fbc..a86158cd3df5 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -154,6 +154,7 @@ class CompilationTests extends ParallelTesting { compileDir("tests/neg-custom-args/adhoc-extension", defaultOptions.and("-strict", "-feature", "-Xfatal-warnings")), compileFile("tests/neg/i7575.scala", defaultOptions.and("-language:_")), compileFile("tests/neg-custom-args/kind-projector.scala", defaultOptions.and("-Ykind-projector")), + compileFile("tests/neg-custom-args/typeclass-derivation2.scala", defaultOptions.and("-Yerased-terms")), ).checkExpectedErrors() } diff --git a/docs/docs/reference/contextual/derivation.md b/docs/docs/reference/contextual/derivation.md index ffbb5ab6de0d..6a5218c39ac6 100644 --- a/docs/docs/reference/contextual/derivation.md +++ b/docs/docs/reference/contextual/derivation.md @@ -165,7 +165,7 @@ worked out example of such a library, see [shapeless 3](https://github.com/miles #### How to write a type class `derived` method using low level mechanisms The low-level method we will use to implement a type class `derived` method in this example exploits three new -type-level constructs in Dotty: inline methods, inline matches, and implicit searches via `summonFrom`. Given this definition of the +type-level constructs in Dotty: inline methods, inline matches, and implicit searches via `summonInline` or `summonFrom`. Given this definition of the `Eq` type class, @@ -194,17 +194,14 @@ call sites (for instance the compiler generated instance definitions in the comp The body of this method (1) first materializes the `Eq` instances for all the child types of type the instance is being derived for. This is either all the branches of a sum type or all the fields of a product type. The -implementation of `summonAll` is `inline` and uses Dotty's `summonFrom` construct to collect the instances as a +implementation of `summonAll` is `inline` and uses Dotty's `summonInline` construct to collect the instances as a `List`, ```scala -inline def summonAll[T]: T = summonFrom { - case t: T => t -} inline def summonAll[T <: Tuple]: List[Eq[_]] = inline erasedValue[T] match { case _: Unit => Nil - case _: (t *: ts) => summon[Eq[t]] :: summonAll[ts] + case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] } ``` @@ -244,15 +241,11 @@ Pulling this all together we have the following complete implementation, ```scala import scala.deriving._ -import scala.compiletime.{erasedValue, summonFrom} - -inline def summon[T]: T = summonFrom { - case t: T => t -} +import scala.compiletime.{erasedValue, summonInline} inline def summonAll[T <: Tuple]: List[Eq[_]] = inline erasedValue[T] match { case _: Unit => Nil - case _: (t *: ts) => summon[Eq[t]] :: summonAll[ts] + case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] } trait Eq[T] { diff --git a/docs/docs/reference/metaprogramming/inline.md b/docs/docs/reference/metaprogramming/inline.md index 25462099ae83..055265a1d482 100644 --- a/docs/docs/reference/metaprogramming/inline.md +++ b/docs/docs/reference/metaprogramming/inline.md @@ -121,9 +121,9 @@ power(expr, 10) ``` Parameters of inline methods can have an `inline` modifier as well. This means -that actual arguments to these parameters will be inlined in the body of the -`inline def`. `inline` parameters have call semantics equivalent to by-name parameters -but allow for duplication of the code in the argument. It is usually useful when constant +that actual arguments to these parameters will be inlined in the body of the +`inline def`. `inline` parameters have call semantics equivalent to by-name parameters +but allow for duplication of the code in the argument. It is usually useful when constant values need to be propagated to allow further optimizations/reductions. The following example shows the difference in translation between by-value, by-name and `inline` @@ -552,6 +552,15 @@ inline def f: Any = summonFrom { } ``` +## `summonInline` + +The shorthand `summonInline` provides a simple way to write a `summon` that is delayed until the call is inlined. +```scala +inline def summonInline[T] <: T = summonFrom { + case t: T => t +} +``` + ### Reference For more info, see [PR #4768](https://github.com/lampepfl/dotty/pull/4768), diff --git a/library/src/scala/compiletime/package.scala b/library/src/scala/compiletime/package.scala index 023183972c88..06cfc8c1cee0 100644 --- a/library/src/scala/compiletime/package.scala +++ b/library/src/scala/compiletime/package.scala @@ -52,6 +52,18 @@ package object compiletime { */ inline def summonFrom[T](f: Nothing => T) <: T = ??? + + /** Summon a given value of type `T`. Usually, the argument is not passed explicitly. + * The summoning is delayed until the call has been fully inlined. + * + * @tparam T the type of the value to be summoned + * @return the given value typed as the provided type parameter + */ + inline def summonInline[T] <: T = summonFrom { + case t: T => t + } + + /** Succesor of a natural number where zero is the type 0 and successors are reduced as if the definition was * * type S[N <: Int] <: Int = N match { diff --git a/tests/neg-custom-args/typeclass-derivation2.scala b/tests/neg-custom-args/typeclass-derivation2.scala index 23bf00cf05c0..7954d1c61151 100644 --- a/tests/neg-custom-args/typeclass-derivation2.scala +++ b/tests/neg-custom-args/typeclass-derivation2.scala @@ -210,12 +210,10 @@ trait Show[T] { def show(x: T): String } object Show { - import scala.compiletime.{erasedValue, error, summonFrom} + import scala.compiletime.{erasedValue, error, summonInline} import TypeLevel._ - inline def tryShow[T](x: T): String = summonFrom { - case s: Show[T] => s.show(x) - } + inline def tryShow[T](x: T): String = summonInline[Show[T]].show(x) inline def showElems[Elems <: Tuple](elems: Mirror, n: Int): List[String] = inline erasedValue[Elems] match { diff --git a/tests/pending/pos/summonFrom.scala b/tests/pending/pos/summonFrom.scala index 52275a90d624..0669609337a1 100644 --- a/tests/pending/pos/summonFrom.scala +++ b/tests/pending/pos/summonFrom.scala @@ -4,9 +4,7 @@ object summonFroms { object invariant { case class Box[T](value: T) implicit val box: Box[Int] = Box(0) - inline def unbox <: Any = summonFrom { - case b: Box[t] => b.value - } + inline def unbox <: Any = summonInline[Box[t]].value val i: Int = unbox val i2 = unbox val i3: Int = i2 @@ -15,9 +13,7 @@ object summonFroms { object covariant { case class Box[+T](value: T) implicit val box: Box[Int] = Box(0) - inline def unbox <: Any = summonFrom { - case b: Box[t] => b.value - } + inline def unbox <: Any = summonInline[Box[t]].value val i: Int = unbox val i2 = unbox val i3: Int = i2 @@ -26,9 +22,7 @@ object summonFroms { object contravariant { case class TrashCan[-T](trash: T => Unit) implicit val trashCan: TrashCan[Int] = TrashCan { i => ; } - inline def trash <: Nothing => Unit = summonFrom { - case c: TrashCan[t] => c.trash - } + inline def trash <: Nothing => Unit = summonInline[TrashCan[t]].trash val t1: Int => Unit = trash val t2 = trash val t3: Int => Unit = t2 diff --git a/tests/pos-macros/i7853/JsonEncoder_1.scala b/tests/pos-macros/i7853/JsonEncoder_1.scala index b0bb1afa6536..856a6b3964b5 100644 --- a/tests/pos-macros/i7853/JsonEncoder_1.scala +++ b/tests/pos-macros/i7853/JsonEncoder_1.scala @@ -6,13 +6,11 @@ trait JsonEncoder[T] { } object JsonEncoder { - import scala.compiletime.{erasedValue, summonFrom} + import scala.compiletime.{erasedValue, summonInline} import compiletime._ import scala.deriving._ - inline def encodeElem[T](elem: T): String = summonFrom { - case encoder: JsonEncoder[T] => encoder.encode(elem) - } + inline def encodeElem[T](elem: T): String = summonInline[JsonEncoder[T]].encode(elem) inline def encodeElems[Elems <: Tuple](idx: Int)(value: Any): List[String] = inline erasedValue[Elems] match { diff --git a/tests/pos-macros/i7853/SummonJsonEncoderTest_2.scala b/tests/pos-macros/i7853/SummonJsonEncoderTest_2.scala index ce9aa435feb2..4891596bfa80 100644 --- a/tests/pos-macros/i7853/SummonJsonEncoderTest_2.scala +++ b/tests/pos-macros/i7853/SummonJsonEncoderTest_2.scala @@ -1,7 +1,5 @@ import scala.deriving._ import scala.quoted._ - -import scala.compiletime.{erasedValue, summonFrom} import JsonEncoder.{given _, _} object SummonJsonEncoderTest { diff --git a/tests/pos-special/typeclass-scaling.scala b/tests/pos-special/typeclass-scaling.scala index 582bdbf1e35b..d7073c5f5556 100644 --- a/tests/pos-special/typeclass-scaling.scala +++ b/tests/pos-special/typeclass-scaling.scala @@ -218,9 +218,7 @@ object typeclasses { import compiletime._ import scala.deriving._ - inline def tryEql[TT](x: TT, y: TT): Boolean = summonFrom { - case eq: Eq[TT] => eq.eql(x, y) - } + inline def tryEql[TT](x: TT, y: TT): Boolean = summonInline[Eq[TT]].eql(x, y) inline def eqlElems[Elems <: Tuple](n: Int)(x: Any, y: Any): Boolean = inline erasedValue[Elems] match { @@ -275,9 +273,7 @@ object typeclasses { def nextInt(buf: mutable.ListBuffer[Int]): Int = try buf.head finally buf.trimStart(1) - inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonFrom { - case pkl: Pickler[T] => pkl.pickle(buf, x) - } + inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonInline[Pickler[T]].pickle(buf, x) inline def pickleElems[Elems <: Tuple](n: Int)(buf: mutable.ListBuffer[Int], x: Any): Unit = inline erasedValue[Elems] match { @@ -298,9 +294,7 @@ object typeclasses { case _: Unit => } - inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonFrom { - case pkl: Pickler[T] => pkl.unpickle(buf) - } + inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonInline[Pickler[T]].unpickle(buf) inline def unpickleElems[Elems <: Tuple](n: Int)(buf: mutable.ListBuffer[Int], elems: ArrayProduct): Unit = inline erasedValue[Elems] match { diff --git a/tests/run-custom-args/typeclass-derivation2.scala b/tests/run-custom-args/typeclass-derivation2.scala index aed502804720..4902977954de 100644 --- a/tests/run-custom-args/typeclass-derivation2.scala +++ b/tests/run-custom-args/typeclass-derivation2.scala @@ -227,9 +227,7 @@ object Eq { import scala.compiletime.{erasedValue, error, summonFrom} import TypeLevel._ - inline def tryEql[T](x: T, y: T) = summonFrom { - case eq: Eq[T] => eq.eql(x, y) - } + inline def tryEql[T](x: T, y: T) = summonInline[Eq[T]].eql(x, y) inline def eqlElems[Elems <: Tuple](xm: Mirror, ym: Mirror, n: Int): Boolean = inline erasedValue[Elems] match { @@ -283,14 +281,12 @@ trait Pickler[T] { } object Pickler { - import scala.compiletime.{erasedValue, constValue, error, summonFrom} + import scala.compiletime.{erasedValue, constValue, error, summonInline} import TypeLevel._ def nextInt(buf: mutable.ListBuffer[Int]): Int = try buf.head finally buf.trimStart(1) - inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonFrom { - case pkl: Pickler[T] => pkl.pickle(buf, x) - } + inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonInline[Pickler[T]].pickle(buf, x) inline def pickleElems[Elems <: Tuple](buf: mutable.ListBuffer[Int], elems: Mirror, n: Int): Unit = inline erasedValue[Elems] match { @@ -321,9 +317,7 @@ object Pickler { case _: Unit => } - inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonFrom { - case pkl: Pickler[T] => pkl.unpickle(buf) - } + inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonInline[Pickler[T]].unpickle(buf) inline def unpickleElems[Elems <: Tuple](buf: mutable.ListBuffer[Int], elems: Array[AnyRef], n: Int): Unit = inline erasedValue[Elems] match { @@ -382,9 +376,7 @@ object Show { import scala.compiletime.{erasedValue, error, summonFrom} import TypeLevel._ - inline def tryShow[T](x: T): String = summonFrom { - case s: Show[T] => s.show(x) - } + inline def tryShow[T](x: T): String = summonInline[Show[T]].show(x) inline def showElems[Elems <: Tuple](elems: Mirror, n: Int): List[String] = inline erasedValue[Elems] match { diff --git a/tests/run-custom-args/typeclass-derivation2c.scala b/tests/run-custom-args/typeclass-derivation2c.scala index abc949c0c542..782da7b9239d 100644 --- a/tests/run-custom-args/typeclass-derivation2c.scala +++ b/tests/run-custom-args/typeclass-derivation2c.scala @@ -1,6 +1,6 @@ import scala.collection.mutable import scala.annotation.tailrec -import scala.compiletime.summonFrom +import scala.compiletime.summonInline // Simulation of an alternative typeclass derivation scheme proposed in #6153 @@ -55,9 +55,7 @@ object Deriving { type CaseLabel <: String /** The represented value */ - inline def singletonValue = summonFrom { - case ev: ValueOf[T] => ev.value - } + inline def singletonValue = summonInline[ValueOf[T]].value } } @@ -213,9 +211,7 @@ trait Eq[T] { object Eq { import scala.compiletime.erasedValue - inline def tryEql[T](x: T, y: T) = summonFrom { - case eq: Eq[T] => eq.eql(x, y) - } + inline def tryEql[T](x: T, y: T) = summonInline[Eq[T]].eql(x, y) inline def eqlElems[Elems <: Tuple](n: Int)(x: Any, y: Any): Boolean = inline erasedValue[Elems] match { @@ -268,9 +264,8 @@ object Pickler { def nextInt(buf: mutable.ListBuffer[Int]): Int = try buf.head finally buf.trimStart(1) - inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonFrom { - case pkl: Pickler[T] => pkl.pickle(buf, x) - } + inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = + summonInline[Pickler[T]].pickle(buf, x) inline def pickleElems[Elems <: Tuple](n: Int)(buf: mutable.ListBuffer[Int], x: Any): Unit = inline erasedValue[Elems] match { @@ -293,9 +288,7 @@ object Pickler { } else pickleCases[T](g, n + 1)(buf, x, ord) - inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonFrom { - case pkl: Pickler[T] => pkl.unpickle(buf) - } + inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonInline[Pickler[T]].unpickle(buf) inline def unpickleElems[Elems <: Tuple](n: Int)(buf: mutable.ListBuffer[Int], elems: Array[AnyRef]): Unit = inline erasedValue[Elems] match { @@ -358,9 +351,7 @@ trait Show[T] { object Show { import scala.compiletime.{erasedValue, constValue} - inline def tryShow[T](x: T): String = summonFrom { - case s: Show[T] => s.show(x) - } + inline def tryShow[T](x: T): String = summonInline[Show[T]].show(x) inline def showElems[Elems <: Tuple, Labels <: Tuple](n: Int)(x: Any): List[String] = inline erasedValue[Elems] match { diff --git a/tests/run/typeclass-derivation-doc-example.scala b/tests/run/typeclass-derivation-doc-example.scala index 905f26b38e16..cf798c74e770 100644 --- a/tests/run/typeclass-derivation-doc-example.scala +++ b/tests/run/typeclass-derivation-doc-example.scala @@ -1,13 +1,9 @@ import scala.deriving._ -import scala.compiletime.{erasedValue, summonFrom} - -inline def summon[T]: T = summonFrom { - case t: T => t -} +import scala.compiletime.{erasedValue, summonInline} inline def summonAll[T <: Tuple]: List[Eq[_]] = inline erasedValue[T] match { case _: Unit => Nil - case _: (t *: ts) => summon[Eq[t]] :: summonAll[ts] + case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] } trait Eq[T] { diff --git a/tests/run/typeclass-derivation1.scala b/tests/run/typeclass-derivation1.scala index 39cf6eeb34f3..7e04c73cd1c4 100644 --- a/tests/run/typeclass-derivation1.scala +++ b/tests/run/typeclass-derivation1.scala @@ -38,9 +38,7 @@ object Deriving { } object Eq { - inline def tryEq[T](x: T, y: T) = summonFrom { - case eq: Eq[T] => eq.equals(x, y) - } + inline def tryEq[T](x: T, y: T) = summonInline[Eq[T]].equals(x, y) inline def deriveForSum[Alts <: Tuple](x: Any, y: Any): Boolean = inline erasedValue[Alts] match { case _: (alt *: alts1) => diff --git a/tests/run/typeclass-derivation2a.scala b/tests/run/typeclass-derivation2a.scala index 67431689c2a8..c126fd1cf4e2 100644 --- a/tests/run/typeclass-derivation2a.scala +++ b/tests/run/typeclass-derivation2a.scala @@ -219,12 +219,10 @@ trait Eq[T] { } object Eq { - import scala.compiletime.{erasedValue, summonFrom} + import scala.compiletime.{erasedValue, summonInline} import TypeLevel._ - inline def tryEql[T](x: T, y: T) = summonFrom { - case eq: Eq[T] => eq.eql(x, y) - } + inline def tryEql[T](x: T, y: T) = summonInline[Eq[T]].eql(x, y) inline def eqlElems[Elems <: Tuple](xm: Mirror, ym: Mirror, n: Int): Boolean = inline erasedValue[Elems] match { @@ -270,14 +268,12 @@ trait Pickler[T] { } object Pickler { - import scala.compiletime.{erasedValue, constValue, summonFrom} + import scala.compiletime.{erasedValue, constValue, summonInline} import TypeLevel._ def nextInt(buf: mutable.ListBuffer[Int]): Int = try buf.head finally buf.trimStart(1) - inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonFrom { - case pkl: Pickler[T] => pkl.pickle(buf, x) - } + inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonInline[Pickler[T]].pickle(buf, x) inline def pickleElems[Elems <: Tuple](buf: mutable.ListBuffer[Int], elems: Mirror, n: Int): Unit = inline erasedValue[Elems] match { @@ -295,9 +291,7 @@ object Pickler { case _: Unit => } - inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonFrom { - case pkl: Pickler[T] => pkl.unpickle(buf) - } + inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonInline[Pickler[T]].unpickle(buf) inline def unpickleElems[Elems <: Tuple](buf: mutable.ListBuffer[Int], elems: Array[AnyRef], n: Int): Unit = inline erasedValue[Elems] match { @@ -357,12 +351,10 @@ trait Show[T] { def show(x: T): String } object Show { - import scala.compiletime.{erasedValue, summonFrom} + import scala.compiletime.{erasedValue, summonInline} import TypeLevel._ - inline def tryShow[T](x: T): String = summonFrom { - case s: Show[T] => s.show(x) - } + inline def tryShow[T](x: T): String = summonInline[Show[T]].show(x) inline def showElems[Elems <: Tuple](elems: Mirror, n: Int): List[String] = inline erasedValue[Elems] match { diff --git a/tests/run/typeclass-derivation2b.scala b/tests/run/typeclass-derivation2b.scala index 5a9144a66259..a2f96ecf206b 100644 --- a/tests/run/typeclass-derivation2b.scala +++ b/tests/run/typeclass-derivation2b.scala @@ -91,12 +91,10 @@ trait Eq[T] { } object Eq { - import scala.compiletime.{erasedValue, summonFrom} + import scala.compiletime.{erasedValue, summonInline} import TypeLevel._ - inline def tryEql[T](x: T, y: T) = summonFrom { - case eq: Eq[T] => eq.eql(x, y) - } + inline def tryEql[T](x: T, y: T) = summonInline[Eq[T]].eql(x, y) inline def eqlElems[Elems <: Tuple](x: Product, y: Product, n: Int): Boolean = inline erasedValue[Elems] match { diff --git a/tests/run/typeclass-derivation2d.scala b/tests/run/typeclass-derivation2d.scala index 600581989416..15f144da4113 100644 --- a/tests/run/typeclass-derivation2d.scala +++ b/tests/run/typeclass-derivation2d.scala @@ -197,11 +197,9 @@ trait Eq[T] { } object Eq { - import scala.compiletime.{erasedValue, summonFrom} + import scala.compiletime.{erasedValue, summonFrom, summonInline} - inline def tryEql[T](x: T, y: T) = summonFrom { - case eq: Eq[T] => eq.eql(x, y) - } + inline def tryEql[T](x: T, y: T) = summonInline[Eq[T]].eql(x, y) inline def eqlElems[Elems <: Tuple](n: Int)(x: Any, y: Any): Boolean = inline erasedValue[Elems] match { @@ -251,13 +249,12 @@ trait Pickler[T] { } object Pickler { - import scala.compiletime.{erasedValue, constValue, summonFrom} + import scala.compiletime.{erasedValue, constValue, summonFrom, summonInline} def nextInt(buf: mutable.ListBuffer[Int]): Int = try buf.head finally buf.trimStart(1) - inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = summonFrom { - case pkl: Pickler[T] => pkl.pickle(buf, x) - } + inline def tryPickle[T](buf: mutable.ListBuffer[Int], x: T): Unit = + summonInline[Pickler[T]].pickle(buf, x) inline def pickleElems[Elems <: Tuple](n: Int)(buf: mutable.ListBuffer[Int], x: Any): Unit = inline erasedValue[Elems] match { @@ -278,9 +275,8 @@ object Pickler { case _: Unit => } - inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = summonFrom { - case pkl: Pickler[T] => pkl.unpickle(buf) - } + inline def tryUnpickle[T](buf: mutable.ListBuffer[Int]): T = + summonInline[Pickler[T]].unpickle(buf) inline def unpickleElems[Elems <: Tuple](n: Int)(buf: mutable.ListBuffer[Int], elems: ArrayProduct): Unit = inline erasedValue[Elems] match { @@ -346,11 +342,9 @@ trait Show[T] { def show(x: T): String } object Show { - import scala.compiletime.{erasedValue, constValue, summonFrom} + import scala.compiletime.{erasedValue, constValue, summonFrom, summonInline} - inline def tryShow[T](x: T): String = summonFrom { - case s: Show[T] => s.show(x) - } + inline def tryShow[T](x: T): String = summonInline[Show[T]].show(x) inline def showElems[Elems <: Tuple, Labels <: Tuple](n: Int)(x: Any): List[String] = inline erasedValue[Elems] match { diff --git a/tests/run/typeclass-derivation3.scala b/tests/run/typeclass-derivation3.scala index 4fc3f6e562aa..68a6c2cf1ffd 100644 --- a/tests/run/typeclass-derivation3.scala +++ b/tests/run/typeclass-derivation3.scala @@ -182,13 +182,11 @@ object typeclasses { def show(x: T): String } object Show { - import scala.compiletime.{erasedValue, summonFrom} + import scala.compiletime.{erasedValue, summonInline} import compiletime._ import deriving._ - inline def tryShow[T](x: T): String = summonFrom { - case s: Show[T] => s.show(x) - } + inline def tryShow[T](x: T): String = summonInline[Show[T]].show(x) inline def showElems[Elems <: Tuple, Labels <: Tuple](n: Int)(x: Any): List[String] = inline erasedValue[Elems] match { @@ -214,11 +212,7 @@ object typeclasses { inline def showCases[Alts <: Tuple](n: Int)(x: Any, ord: Int): String = inline erasedValue[Alts] match { case _: (alt *: alts1) => - if (ord == n) - summonFrom { - case m: Mirror.ProductOf[`alt`] => - showCase(x, m) - } + if (ord == n) showCase(x, summonInline[Mirror.ProductOf[`alt`]]) else showCases[alts1](n + 1)(x, ord) case _: Unit => throw new MatchError(x)