@@ -32,6 +32,8 @@ trait Deriving { this: Typer =>
3232 /** A buffer for synthesized symbols */
3333 private var synthetics = new mutable.ListBuffer [Symbol ]
3434
35+ private var derivesGeneric = false
36+
3537 /** the children of `cls` ordered by textual occurrence */
3638 lazy val children : List [Symbol ] = cls.children
3739
@@ -170,7 +172,7 @@ trait Deriving { this: Typer =>
170172 val derivedType = checkClassType(underlyingType, derived.sourcePos, traitReq = false , stablePrefixReq = true )
171173 val nparams = derivedType.classSymbol.typeParams.length
172174 if (derivedType.isRef(defn.GenericClass ))
173- () // do nothing, a Generic instance will be created anyway by `addGeneric`
175+ derivesGeneric = true
174176 else if (nparams == 1 ) {
175177 val typeClass = derivedType.classSymbol
176178 val firstKindedParams = cls.typeParams.filterNot(_.info.isLambdaSub)
@@ -210,14 +212,33 @@ trait Deriving { this: Typer =>
210212 addDerivedInstance(defn.GenericType .name, genericCompleter, codePos, reportErrors = false )
211213 }
212214
215+ /** If any of the instances has a companion with a `derived` member
216+ * that refers to `scala.reflect.Generic`, add an implied instance
217+ * of `Generic`. Note: this is just an optimization to avoid possible
218+ * code duplication. Generic instances are created on the fly if they
219+ * are missing from the companion.
220+ */
221+ private def maybeAddGeneric (): Unit = {
222+ val genericCls = defn.GenericClass
223+ def refersToGeneric (sym : Symbol ): Boolean = {
224+ val companion = sym.info.finalResultType.classSymbol.companionModule
225+ val derivd = companion.info.member(nme.derived)
226+ derivd.hasAltWith(sd => sd.info.existsPart(p => p.typeSymbol == genericCls))
227+ }
228+ if (derivesGeneric || synthetics.exists(refersToGeneric)) {
229+ derive.println(i " add generic infrastructure for $cls" )
230+ addGeneric()
231+ addGenericClass()
232+ }
233+ }
234+
213235 /** Create symbols for derived instances and infrastructure,
214- * append them to `synthetics` buffer,
215- * and enter them into class scope .
236+ * append them to `synthetics` buffer, and enter them into class scope.
237+ * Also, add generic instances if needed .
216238 */
217239 def enterDerived (derived : List [untpd.Tree ]) = {
218240 derived.foreach(processDerivedInstance(_))
219- addGeneric()
220- addGenericClass()
241+ maybeAddGeneric()
221242 }
222243
223244 private def tupleElems (tp : Type ): List [Type ] = tp match {
0 commit comments