I am looking through this article. They have the following code:
inline def labels[Labels <: Tuple](using Tuple.Union[Labels] <:< String): List[String] =
inline erasedValue[Labels] match {
case _: EmptyTuple =>
List.empty
case _: (head *: tail) =>
constValue[head].asInstanceOf[String] :: labels[tail]
}
This fails with the following error:
[error] 108 | constValue[head].asInstanceOf[String] :: labels2[tail]
[error] | ^
[error] | Cannot prove that Tuple.Union[tail]
[error] |
[error] | where: tail is a type in method labels2 with bounds <: Tuple
[error] | <:< String..
[error] | I found:
[error] |
[error] | t
[error] |
[error] | But parameter t does not match type Tuple.Union[tail] <:< String.
[error] |
[error] | Note: a match type could not be fully reduced:
[error] |
[error] | trying to reduce Tuple.Union[tail]
[error] | trying to reduce scala.Tuple.Fold[tail, Nothing, [x, y] =>> x | y]
[error] | failed since selector tail
[error] | does not match case EmptyTuple => Nothing
[error] | and cannot be shown to be disjoint from it either.
[error] | Therefore, reduction cannot advance to the remaining case
[error] |
[error] | case h *: t => h | scala.Tuple.Fold[t, Nothing, [x, y] =>> x | y]
The code looks correct so I created this code online (slight change to using, named it t
):
and tried several versions of Scala 3.x.y. They consistently give the same error. Intuitively I would say that if a tuple has all member types T
, then any subset of that tuple will also have that same type T
. The compiler does not seem to infer this.
So my questions are:
- Am I thinking correctly?
- What can I do to let the compiler infer the desired type?
TIA,
HF