Skip to content

Commit 0992722

Browse files
committed
Auto-generated derived typeclass instances
... except for Shaped, which is still a todo.
1 parent c438299 commit 0992722

File tree

3 files changed

+37
-19
lines changed

3 files changed

+37
-19
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ object StdNames {
398398
val definitions: N = "definitions"
399399
val delayedInit: N = "delayedInit"
400400
val delayedInitArg: N = "delayedInit$body"
401+
val derived: N = "derived"
401402
val derives: N = "derives"
402403
val drop: N = "drop"
403404
val dynamics: N = "dynamics"

compiler/src/dotty/tools/dotc/typer/Deriving.scala

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,15 @@ trait Deriving { this: Typer =>
117117
/** Enter type class instance with given name and info in current scope, provided
118118
* an instance woth the same name does not exist already.
119119
*/
120-
private def addDerivedInstance(clsName: Name, info: Type, reportErrors: Boolean) = {
120+
private def addDerivedInstance(clsName: Name, info: Type, reportErrors: Boolean, implicitFlag: FlagSet = Implicit) = {
121121
val instanceName = s"derived$$$clsName".toTermName
122122
if (ctx.denotNamed(instanceName).exists) {
123123
if (reportErrors) ctx.error(i"duplicate typeclass derivation for $clsName")
124124
}
125-
else
126-
add(ctx.newSymbol(ctx.owner, instanceName, Synthetic | Method, info, coord = cls.pos))
125+
else {
126+
val implFlag = if (reportErrors) Implicit else EmptyFlags // for now
127+
add(ctx.newSymbol(ctx.owner, instanceName, Synthetic | Method | implFlag, info, coord = cls.pos.startPos))
128+
}
127129
}
128130

129131
/* Check derived type tree `derived` for the following well-formedness conditions:
@@ -176,16 +178,31 @@ trait Deriving { this: Typer =>
176178
def implementedClass(instance: Symbol) =
177179
instance.info.stripPoly.finalResultType.classSymbol
178180

179-
def typeclassInstance(sym: Symbol)(tparamRefs: List[Type])(paramRefss: List[List[tpd.Tree]]): tpd.Tree = {
180-
val tparams = tparamRefs.map(_.typeSymbol.asType)
181-
val params = if (paramRefss.isEmpty) Nil else paramRefss.head.map(_.symbol.asTerm)
182-
val typeCls = implementedClass(sym)
183-
tpd.ref(defn.Predef_undefinedR) // TODO: flesh out
184-
}
181+
private def typeclassInstance(sym: Symbol)(implicit ctx: Context) =
182+
(tparamRefs: List[Type]) => (paramRefss: List[List[tpd.Tree]]) => {
183+
val tparams = tparamRefs.map(_.typeSymbol.asType)
184+
val params = if (paramRefss.isEmpty) Nil else paramRefss.head.map(_.symbol.asTerm)
185+
tparams.foreach(ctx.enter)
186+
params.foreach(ctx.enter)
187+
def instantiated(info: Type): Type = info match {
188+
case info: PolyType => instantiated(info.instantiate(tparamRefs))
189+
case info: MethodType => info.instantiate(params.map(_.termRef))
190+
case info => info
191+
}
192+
val resultType = instantiated(sym.info)
193+
val typeCls = resultType.classSymbol
194+
if (typeCls == defn.ShapedClass)
195+
tpd.ref(defn.Predef_undefinedR) // TODO: flesh out
196+
else {
197+
val module = untpd.ref(typeCls.companionModule.termRef).withPos(sym.pos)
198+
val rhs = untpd.Select(module, nme.derived)
199+
typed(rhs, resultType)
200+
}
201+
}
185202

186203
def syntheticDef(sym: Symbol): tpd.Tree =
187204
if (sym.isType) tpd.TypeDef(sym.asType)
188-
else tpd.polyDefDef(sym.asTerm, typeclassInstance(sym))
205+
else tpd.polyDefDef(sym.asTerm, typeclassInstance(sym)(ctx.fresh.setOwner(sym).setNewScope))
189206

190207
def finalize(stat: tpd.TypeDef): tpd.Tree = {
191208
val templ @ Template(_, _, _, _) = stat.rhs

tests/run/typeclass-derivation3.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ object datatypes {
3636
}
3737

3838
// three clauses that could be generated from a `derives` clause
39-
implicit def LstEq[T: Eq]: Eq[Lst[T]] = Eq.derived
40-
implicit def LstPickler[T: Pickler]: Pickler[Lst[T]] = Pickler.derived
41-
implicit def LstShow[T: Show]: Show[Lst[T]] = Show.derived
39+
//implicit def LstEq[T: Eq]: Eq[Lst[T]] = Eq.derived
40+
//implicit def LstPickler[T: Pickler]: Pickler[Lst[T]] = Pickler.derived
41+
//implicit def LstShow[T: Show]: Show[Lst[T]] = Show.derived
4242
}
4343

4444
// A simple product type
@@ -62,9 +62,9 @@ object datatypes {
6262
}
6363

6464
// two clauses that could be generated from a `derives` clause
65-
implicit def PairEq[T: Eq]: Eq[Pair[T]] = Eq.derived
66-
implicit def PairPickler[T: Pickler]: Pickler[Pair[T]] = Pickler.derived
67-
implicit def PairShow[T: Show]: Show[Pair[T]] = Show.derived
65+
//implicit def PairEq[T: Eq]: Eq[Pair[T]] = Eq.derived
66+
//implicit def PairPickler[T: Pickler]: Pickler[Pair[T]] = Pickler.derived
67+
//implicit def PairShow[T: Show]: Show[Pair[T]] = Show.derived
6868
}
6969

7070
sealed trait Either[+L, +R] extends Product derives Eq, Pickler, Show
@@ -95,9 +95,9 @@ object datatypes {
9595
def common = reflectedClass
9696
}
9797

98-
implicit def EitherEq[L: Eq, R: Eq]: Eq[Either[L, R]] = Eq.derived
99-
implicit def EitherPickler[L: Pickler, R: Pickler]: Pickler[Either[L, R]] = Pickler.derived
100-
implicit def EitherShow[L: Show, R: Show]: Show[Either[L, R]] = Show.derived
98+
//implicit def EitherEq[L: Eq, R: Eq]: Eq[Either[L, R]] = Eq.derived
99+
//implicit def EitherPickler[L: Pickler, R: Pickler]: Pickler[Either[L, R]] = Pickler.derived
100+
//implicit def EitherShow[L: Show, R: Show]: Show[Either[L, R]] = Show.derived
101101
}
102102
}
103103

0 commit comments

Comments
 (0)