@@ -61,21 +61,19 @@ trait Deriving { this: Typer =>
6161
6262 /** Check derived type tree `derived` for the following well-formedness conditions:
6363 * (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 ...
6964 *
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
7271 *
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.
7473 *
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.
7775 *
78- * See test run/typeclass-derivation2 and run /derive-multi
76+ * See test run/typeclass-derivation2, run/poly-kinded-derives and pos /derive-eq
7977 * for examples that spell out what would be generated.
8078 *
8179 * Note that the name of the derived method contains the name in the derives clause, not
@@ -86,6 +84,8 @@ trait Deriving { this: Typer =>
8684 val originalTypeClassType = typedAheadType(derived, AnyTypeConstructorProto ).tpe
8785 val typeClassType = checkClassType(underlyingClassRef(originalTypeClassType), derived.sourcePos, traitReq = false , stablePrefixReq = true )
8886 val typeClass = typeClassType.classSymbol
87+ val typeClassParams = typeClass.typeParams
88+ val typeClassArity = typeClassParams.length
8989
9090 def sameParamKinds (xs : List [ParamInfo ], ys : List [ParamInfo ]): Boolean =
9191 xs.corresponds(ys)((x, y) => x.paramInfo.hasSameKindAs(y.paramInfo))
@@ -102,10 +102,8 @@ trait Deriving { this: Typer =>
102102 addDerivedInstance(originalTypeClassType.typeSymbol.name, derivedInfo, derived.sourcePos)
103103 }
104104
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
109107 //
110108 // (a) ADT and type class parameters overlap on the right and have the
111109 // same kinds at the overlap.
@@ -161,6 +159,7 @@ trait Deriving { this: Typer =>
161159 val alignedClsParamInfos = clsParamInfos.takeRight(instanceArity)
162160 val alignedTypeClassParamInfos = typeClassParamInfos.take(alignedClsParamInfos.length)
163161
162+
164163 if ((instanceArity == clsArity || instanceArity > 0 ) && sameParamKinds(alignedClsParamInfos, alignedTypeClassParamInfos)) {
165164 // case (a) ... see description above
166165 val derivedParams = clsParams.dropRight(instanceArity)
@@ -182,8 +181,10 @@ trait Deriving { this: Typer =>
182181 addInstance(clsParams, evidenceParamInfos, List (instanceType))
183182 } else
184183 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
187188 //
188189 // This has been extracted from the earlier more general multi-parameter
189190 // type class model. Modulo the assumptions below, the implied semantics
@@ -243,7 +244,11 @@ trait Deriving { this: Typer =>
243244
244245 // Eql[A[T_L, U_L, V_L], A[T_R, U_R, V_R]]
245246 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 )
247252 ctx.error(i " type ${typeClass.name} in derives clause of ${cls.name} has no type parameters " , derived.sourcePos)
248253 else
249254 cannotBeUnified
0 commit comments