@@ -61,21 +61,19 @@ trait Deriving { this: Typer =>
61
61
62
62
/** Check derived type tree `derived` for the following well-formedness conditions:
63
63
* (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix)
64
- * (2) It must have exactly one type parameter
65
- * If it passes the checks, enter a typeclass instance for it in the current scope.
66
- * Given
67
- *
68
- * class C[Ts] .... derives ... D ...
69
64
*
70
- * where `T_1, ..., T_n` are the first-kinded type parameters in `Ts`,
71
- * the typeclass instance has the form
65
+ * (2) It must belong to one of the following three categories:
66
+ * (a) a single paramter type class with a parameter which matches the kind of
67
+ * the deriving ADT
68
+ * (b) a single parameter type class with a parameter of kind * and an ADT with
69
+ * one or more type parameter of kind *
70
+ * (c) the Eql type class
72
71
*
73
- * implicit def derived$D(implicit ev_1: D[T_1], ..., ev_n: D[T_n]): D[C[Ts]] = D.derived
72
+ * See detailed descriptions in deriveSingleParameter and deriveEql below.
74
73
*
75
- * See the body of this method for how to generalize this to typeclasses with more
76
- * or less than one type parameter.
74
+ * If it passes the checks, enter a typeclass instance for it in the current scope.
77
75
*
78
- * See test run/typeclass-derivation2 and run /derive-multi
76
+ * See test run/typeclass-derivation2, run/poly-kinded-derives and pos /derive-eq
79
77
* for examples that spell out what would be generated.
80
78
*
81
79
* Note that the name of the derived method contains the name in the derives clause, not
@@ -86,6 +84,8 @@ trait Deriving { this: Typer =>
86
84
val originalTypeClassType = typedAheadType(derived, AnyTypeConstructorProto ).tpe
87
85
val typeClassType = checkClassType(underlyingClassRef(originalTypeClassType), derived.sourcePos, traitReq = false , stablePrefixReq = true )
88
86
val typeClass = typeClassType.classSymbol
87
+ val typeClassParams = typeClass.typeParams
88
+ val typeClassArity = typeClassParams.length
89
89
90
90
def sameParamKinds (xs : List [ParamInfo ], ys : List [ParamInfo ]): Boolean =
91
91
xs.corresponds(ys)((x, y) => x.paramInfo.hasSameKindAs(y.paramInfo))
@@ -102,10 +102,8 @@ trait Deriving { this: Typer =>
102
102
addDerivedInstance(originalTypeClassType.typeSymbol.name, derivedInfo, derived.sourcePos)
103
103
}
104
104
105
- val typeClassParams = typeClass.typeParams
106
- val typeClassArity = typeClassParams.length
107
- if (typeClassArity == 1 ) {
108
- // Primary case: single parameter type classes
105
+ def deriveSingleParameter : Unit = {
106
+ // Single parameter type classes ... (a) and (b) above
109
107
//
110
108
// (a) ADT and type class parameters overlap on the right and have the
111
109
// same kinds at the overlap.
@@ -161,6 +159,7 @@ trait Deriving { this: Typer =>
161
159
val alignedClsParamInfos = clsParamInfos.takeRight(instanceArity)
162
160
val alignedTypeClassParamInfos = typeClassParamInfos.take(alignedClsParamInfos.length)
163
161
162
+
164
163
if ((instanceArity == clsArity || instanceArity > 0 ) && sameParamKinds(alignedClsParamInfos, alignedTypeClassParamInfos)) {
165
164
// case (a) ... see description above
166
165
val derivedParams = clsParams.dropRight(instanceArity)
@@ -182,8 +181,10 @@ trait Deriving { this: Typer =>
182
181
addInstance(clsParams, evidenceParamInfos, List (instanceType))
183
182
} else
184
183
cannotBeUnified
185
- } else if (typeClass == defn.EqlClass ) {
186
- // Special case: derives semantics for the Eql type class
184
+ }
185
+
186
+ def deriveEql : Unit = {
187
+ // Specific derives rules for the Eql type class ... (c) above
187
188
//
188
189
// This has been extracted from the earlier more general multi-parameter
189
190
// type class model. Modulo the assumptions below, the implied semantics
@@ -243,7 +244,11 @@ trait Deriving { this: Typer =>
243
244
244
245
// Eql[A[T_L, U_L, V_L], A[T_R, U_R, V_R]]
245
246
addInstance(clsParamss.flatten, evidenceParamInfos, instanceTypes)
246
- } else if (typeClassArity == 0 )
247
+ }
248
+
249
+ if (typeClassArity == 1 ) deriveSingleParameter
250
+ else if (typeClass == defn.EqlClass ) deriveEql
251
+ else if (typeClassArity == 0 )
247
252
ctx.error(i " type ${typeClass.name} in derives clause of ${cls.name} has no type parameters " , derived.sourcePos)
248
253
else
249
254
cannotBeUnified
0 commit comments