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