@@ -12,34 +12,40 @@ class data extends MacroAnnotation:
12
12
val classPatches = ArrayBuffer [String ]()
13
13
14
14
val cls = tree.symbol
15
- val expectedBody = s " data.generated[ ${cls.name}]() " // FIXME: handle type parameters
15
+ val typeParams = cdef.body.map(_.symbol).filter(_.isType)
16
+ val clsTpe =
17
+ if typeParams.isEmpty then cls.typeRef
18
+ else AppliedType (cls.typeRef, typeParams.map(_.typeRef))
19
+ clsTpe.asType match
20
+ case ' [t] =>
21
+ val expectedBody = ' { data.generated[t]() }.show
16
22
17
- val params = paramNames(cls)
18
- for param <- params do
19
- val withParam = With (param)
20
- val paramType = cls.declaredField(param).info
21
- val existingOpt =
22
- cdef.body.find(stat =>
23
- val paramss = stat.symbol.paramSymss
24
- stat.symbol.name == withParam
25
- && paramss.size == 1 && paramss(0 ).size == 1
26
- && paramss(0 )(0 ).name == param // FIXME: if the parameter name is incorrect, propose rewriting it
27
- && paramss(0 )(0 ).info == paramType // FIXME: if the parameter type changed, propose rewriting it
28
- )
29
- existingOpt match
30
- case Some (tree : DefDef ) =>
31
- tree.rhs match
32
- case Some (rhs) => rhs.asExpr match
33
- case ' {data.generated[t]()} =>
34
- // The correct method is already present, nothing to do
35
- case _ =>
36
- report.error(s " Replace the underline code by: \n $expectedBody" , rhs.pos)
23
+ val params = paramNames(cls)
24
+ for param <- params do
25
+ val withParam = With (param)
26
+ val paramType = cls.declaredField(param).info
27
+ val existingOpt =
28
+ cdef.body.find(stat =>
29
+ val paramss = stat.symbol.paramSymss
30
+ stat.symbol.name == withParam
31
+ && paramss.size == 1 && paramss(0 ).size == 1
32
+ && paramss(0 )(0 ).name == param // FIXME: if the parameter name is incorrect, propose rewriting it
33
+ && paramss(0 )(0 ).info == paramType // FIXME: if the parameter type changed, propose rewriting it
34
+ )
35
+ existingOpt match
36
+ case Some (tree : DefDef ) =>
37
+ tree.rhs match
38
+ case Some (rhs) => rhs.asExpr match
39
+ case ' {data.generated[`t`]()} =>
40
+ // The correct method is already present, nothing to do
41
+ case _ =>
42
+ report.error(s " Replace the underline code by: \n $expectedBody" , rhs.pos)
43
+ case _ =>
44
+ report.error(s " Replace the underline code by: \n ${tree.show} = $expectedBody" , tree.pos)
37
45
case _ =>
38
- report.error(s " Replace the underline code by: \n ${tree.show} = $expectedBody" , tree.pos)
39
- case _ =>
40
- // The method is not present
41
- classPatches +=
42
- s " def $withParam( $param: ${paramType.show}): ${cls.name} = $expectedBody"
46
+ // The method is not present
47
+ classPatches +=
48
+ s " def $withParam( $param: ${paramType.show}): ${Type .show[t]} = $expectedBody"
43
49
44
50
45
51
val ctr = cdef.constructor
@@ -53,6 +59,7 @@ class data extends MacroAnnotation:
53
59
List (tree)
54
60
55
61
object data :
62
+ // TODO: Is T necessary? Could this be transparent?
56
63
inline def generated [T ](): T = $ {generatedImpl[T ]}
57
64
private def generatedImpl [T : Type ](using Quotes ): Expr [T ] =
58
65
import quotes .reflect .*
@@ -62,15 +69,15 @@ object data:
62
69
meth.name match
63
70
case With (paramName) =>
64
71
val localParam = meth.paramSymss(0 )(0 )
65
- val body =
72
+ val body = // FIXME handle type parameters
66
73
Apply (Select (New (TypeIdent (cls)), cls.primaryConstructor),
67
74
params.map(p => if p == paramName then Ref (localParam) else Ref (cls.declaredField(p))))
68
75
body.asExprOf[T ]
69
76
case _ =>
70
77
report.errorAndAbort(" @data.generated used in invalid context" )
71
78
72
79
def paramNames (using Quotes )(cls : quotes.reflect.Symbol ): List [String ] =
73
- cls.primaryConstructor.paramSymss.head.map(_.name)
80
+ cls.primaryConstructor.paramSymss.dropWhile(_.headOption.exists(_.isType)). head.map(_.name)
74
81
75
82
private object With :
76
83
def apply (paramName : String ): String =
0 commit comments