1+ import scala .annotation .{tailrec , unused }
2+ import scala .deriving .Mirror
3+ import scala .quoted .*
4+
5+ trait TypeLength [A ] {
6+ type Length <: Int
7+ def length : Length
8+ }
9+ object TypeLength extends TypeLengthLowPriority :
10+ type Aux [A , Length0 <: Int ] = TypeLength [A ] {
11+ type Length = Length0
12+ }
13+
14+ transparent inline given fromMirror [A ](using m : Mirror .Of [A ]): TypeLength [A ] =
15+ $ { macroImpl[A , m.MirroredElemTypes ] }
16+
17+ @ tailrec
18+ private def typesOfTuple (
19+ using q : Quotes
20+ )(tpe : q.reflect.TypeRepr , acc : List [q.reflect.TypeRepr ]): List [q.reflect.TypeRepr ] =
21+ import q .reflect .*
22+ val cons = Symbol .classSymbol(" scala.*:" )
23+ tpe.widenTermRefByName.dealias match
24+ case AppliedType (fn, tpes) if defn.isTupleClass(fn.typeSymbol) =>
25+ tpes.reverse_::: (acc)
26+ case AppliedType (tp, List (headType, tailType)) if tp.derivesFrom(cons) =>
27+ typesOfTuple(tailType, headType :: acc)
28+ case tpe =>
29+ if tpe.derivesFrom(Symbol .classSymbol(" scala.EmptyTuple" )) then acc.reverse
30+ else report.errorAndAbort(s " Unknown type encountered in tuple ${tpe.show}" )
31+
32+ def macroImpl [A : Type , T <: Tuple : scala.quoted.Type ](
33+ using q : scala.quoted.Quotes
34+ ): scala.quoted.Expr [TypeLength [A ]] =
35+ import q .reflect .*
36+ val l = typesOfTuple(TypeRepr .of[T ], Nil ).length
37+ ConstantType (IntConstant (l)).asType match
38+ case ' [lt] =>
39+ val le = Expr [Int ](l).asExprOf[lt & Int ]
40+ ' {
41+ val r : TypeLength .Aux [A , lt & Int ] = new TypeLength [A ] {
42+ type Length = lt & Int
43+ val length : Length = $ { le }
44+ }
45+ r
46+ }
47+
48+ transparent inline given fromTuple [T <: Tuple ]: TypeLength [T ] =
49+ $ { macroImpl[T , T ] }
50+
51+ trait TypeLengthLowPriority :
52+ self : TypeLength .type =>
53+ given tupleFromMirrorAndLength [A , T <: Tuple ](
54+ using @ unused m : Mirror .Of [A ] { type MirroredElemTypes = T },
55+ length : TypeLength [A ]
56+ ): TypeLength .Aux [T , length.Length ] = length.asInstanceOf [TypeLength .Aux [T , length.Length ]]
57+
58+ trait HKDSumGeneric [A ]
59+ object HKDSumGeneric :
60+ type NotZero [N <: Int ] = N match
61+ case 0 => false
62+ case _ => true
63+
64+ transparent inline given derived [A ](using m : Mirror .SumOf [A ], typeLength : TypeLength [A ])(
65+ using NotZero [typeLength.Length ] =:= true
66+ ): HKDSumGeneric [A ] =
67+ derivedImpl[A , m.MirroredElemTypes , m.MirroredLabel ] // error
68+
69+ def derivedImpl [A , ElemTypes <: Tuple , Label <: String ](
70+ using m : Mirror .SumOf [A ] {
71+ type MirroredElemTypes = ElemTypes ; type MirroredLabel = Label ;
72+ },
73+ typeLength : TypeLength [ElemTypes ],
74+ nz : NotZero [typeLength.Length ] =:= true
75+ ): HKDSumGeneric [A ] = ???
0 commit comments