@@ -161,33 +161,67 @@ trait Deriving { this: Typer =>
161
161
*
162
162
* implicit def derived$D(implicit ev_1: D[T_1], ..., ev_n: D[T_n]): D[C[Ts]] = D.derived
163
163
*
164
- * See test run/typeclass-derivation2 for examples that spell out what would be generated.
165
- * Note that the name of the derived method containd the name in the derives clause, not
164
+ * See the body of this method for who to generalize this to typeclasses with more
165
+ * or less than one type parameter.
166
+ *
167
+ * See test run/typeclass-derivation2 and run/derive-multi
168
+ * for examples that spell out what would be generated.
169
+ *
170
+ * Note that the name of the derived method contains the name in the derives clause, not
166
171
* the underlying class name. This allows one to disambiguate derivations of type classes
167
172
* that have the same name but different prefixes through selective aliasing.
168
173
*/
169
174
private def processDerivedInstance (derived : untpd.Tree ): Unit = {
170
175
val originalType = typedAheadType(derived, AnyTypeConstructorProto ).tpe
171
176
val underlyingType = underlyingClassRef(originalType)
172
177
val derivedType = checkClassType(underlyingType, derived.sourcePos, traitReq = false , stablePrefixReq = true )
173
- val nparams = derivedType.classSymbol.typeParams.length
178
+ val typeClass = derivedType.classSymbol
179
+ val nparams = typeClass.typeParams.length
174
180
if (derivedType.isRef(defn.GenericClass ))
175
181
derivesGeneric = true
176
- else if (nparams == 1 ) {
177
- val typeClass = derivedType.classSymbol
178
- val firstKindedParams = cls.typeParams.filterNot(_.info.isLambdaSub)
182
+ else {
183
+ // A matrix of all parameter combinations of current class parameters
184
+ // and derived typeclass parameters.
185
+ // Rows: parameters of current class
186
+ // Columns: parameters of typeclass
187
+
188
+ // Running example: typeclass: class TC[X, Y, Z], deriving class: class A[T, U]
189
+ // clsParamss =
190
+ // T_X T_Y T_Z
191
+ // U_X U_Y U_Z
192
+ val clsParamss : List [List [TypeSymbol ]] = cls.typeParams.map { tparam =>
193
+ if (nparams == 0 ) Nil
194
+ else if (nparams == 1 ) tparam :: Nil
195
+ else typeClass.typeParams.map(tcparam =>
196
+ tparam.copy(name = s " ${tparam.name}_ ${tcparam.name}" .toTypeName)
197
+ .asInstanceOf [TypeSymbol ])
198
+ }
199
+ val firstKindedParamss = clsParamss.filter {
200
+ case param :: _ => ! param.info.isLambdaSub
201
+ case nil => false
202
+ }
203
+
204
+ // The types of the required evidence parameters. In the running example:
205
+ // TC[T_X, T_Y, T_Z], TC[U_X, U_Y, U_Z]
179
206
val evidenceParamInfos =
180
- for (param <- firstKindedParams) yield derivedType.appliedTo(param.typeRef)
181
- val resultType = derivedType.appliedTo(cls.appliedRef)
207
+ for (row <- firstKindedParamss)
208
+ yield derivedType.appliedTo(row.map(_.typeRef))
209
+
210
+ // The class instances in the result type. Running example:
211
+ // A[T_X, U_X], A[T_Y, U_Y], A[T_Z, U_Z]
212
+ val resultInstances =
213
+ for (n <- List .range(0 , nparams))
214
+ yield cls.typeRef.appliedTo(clsParamss.map(row => row(n).typeRef))
215
+
216
+ // TC[A[T_X, U_X], A[T_Y, U_Y], A[T_Z, U_Z]]
217
+ val resultType = derivedType.appliedTo(resultInstances)
218
+
219
+ val clsParams : List [TypeSymbol ] = clsParamss.flatten
182
220
val instanceInfo =
183
- if (cls.typeParams .isEmpty) ExprType (resultType)
184
- else PolyType .fromParams(cls.typeParams , ImplicitMethodType (evidenceParamInfos, resultType))
221
+ if (clsParams .isEmpty) ExprType (resultType)
222
+ else PolyType .fromParams(clsParams , ImplicitMethodType (evidenceParamInfos, resultType))
185
223
addDerivedInstance(originalType.typeSymbol.name, instanceInfo, derived.sourcePos, reportErrors = true )
186
224
}
187
- else
188
- ctx.error(
189
- i " derived class $derivedType should have one type paramater but has $nparams" ,
190
- derived.sourcePos)
191
225
}
192
226
193
227
/** Add value corresponding to `val genericClass = new GenericClass(...)`
0 commit comments