Skip to content

Commit 47c3265

Browse files
committed
Represent derives clauses in Template trees
with implementation of their desugaring
1 parent 5c65fc5 commit 47c3265

File tree

19 files changed

+120
-60
lines changed

19 files changed

+120
-60
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ object desugar {
296296
/** The expansion of a class definition. See inline comments for what is involved */
297297
def classDef(cdef: TypeDef)(implicit ctx: Context): Tree = {
298298
val className = checkNotReservedName(cdef).asTypeName
299-
val impl @ Template(constr0, parents, self, _) = cdef.rhs
299+
val impl @ Template(_, _, self, _) = cdef.rhs
300+
val parents = impl.parents
300301
val mods = cdef.mods
301302
val companionMods = mods
302303
.withFlags((mods.flags & (AccessFlags | Final)).toCommonFlags)
@@ -311,7 +312,7 @@ object desugar {
311312
meth
312313
}
313314

314-
val constr1 = decompose(defDef(constr0, isPrimaryConstructor = true))
315+
val constr1 = decompose(defDef(impl.constr, isPrimaryConstructor = true))
315316

316317
// The original type and value parameters in the constructor already have the flags
317318
// needed to be type members (i.e. param, and possibly also private and local unless
@@ -535,12 +536,16 @@ object desugar {
535536
}
536537
def eqInstances = if (isEnum) eqInstance :: Nil else Nil
537538

539+
// derived type classes of non-module classes go to their companions
540+
val (clsDerived, companionDerived) =
541+
if (mods.is(Module)) (impl.derived, Nil) else (Nil, impl.derived)
542+
538543
// The thicket which is the desugared version of the companion object
539-
// synthetic object C extends parentTpt { defs }
544+
// synthetic object C extends parentTpt derives class-derived { defs }
540545
def companionDefs(parentTpt: Tree, defs: List[Tree]) =
541546
moduleDef(
542547
ModuleDef(
543-
className.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs))
548+
className.toTermName, Template(emptyConstructor, parentTpt :: Nil, companionDerived, EmptyValDef, defs))
544549
.withMods(companionMods | Synthetic))
545550
.withPos(cdef.pos).toList
546551

@@ -591,10 +596,10 @@ object desugar {
591596
}
592597
companionDefs(companionParent, applyMeths ::: unapplyMeth :: companionMembers)
593598
}
594-
else if (companionMembers.nonEmpty)
599+
else if (companionMembers.nonEmpty || companionDerived.nonEmpty)
595600
companionDefs(anyRef, companionMembers)
596601
else if (isValueClass) {
597-
constr0.vparamss match {
602+
impl.constr.vparamss match {
598603
case (_ :: Nil) :: _ => companionDefs(anyRef, Nil)
599604
case _ => Nil // error will be emitted in typer
600605
}
@@ -653,7 +658,7 @@ object desugar {
653658
}
654659
cpy.TypeDef(cdef: TypeDef)(
655660
name = className,
656-
rhs = cpy.Template(impl)(constr, parents1, self1,
661+
rhs = cpy.Template(impl)(constr, parents1, clsDerived, self1,
657662
tparamAccessors ::: vparamAccessors ::: normalizedBody ::: caseClassMeths)): TypeDef
658663
}
659664

@@ -739,7 +744,7 @@ object desugar {
739744
val localType = tdef.withMods(Modifiers(Synthetic | Opaque).withPrivateWithin(tdef.name))
740745

741746
val companions = moduleDef(ModuleDef(
742-
moduleName, Template(emptyConstructor, Nil, EmptyValDef, localType :: Nil))
747+
moduleName, Template(emptyConstructor, Nil, Nil, EmptyValDef, localType :: Nil))
743748
.withFlags(Synthetic | Opaque))
744749
Thicket(aliasType :: companions.toList)
745750
}
@@ -1297,7 +1302,7 @@ object desugar {
12971302
val (classParents, self) =
12981303
if (parentCores.length == 1 && (parent.tpe eq parentCores.head)) (untpdParent :: Nil, EmptyValDef)
12991304
else (parentCores map TypeTree, ValDef(nme.WILDCARD, untpdParent, EmptyTree))
1300-
val impl = Template(emptyConstructor, classParents, self, refinements)
1305+
val impl = Template(emptyConstructor, classParents, Nil, self, refinements)
13011306
TypeDef(tpnme.REFINE_CLASS, impl).withFlags(Trait)
13021307
}
13031308

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ object DesugarEnums {
114114
val toStringDef =
115115
DefDef(nme.toString_, Nil, Nil, TypeTree(), Ident(nme.name))
116116
.withFlags(Override)
117-
def creator = New(Template(emptyConstructor, enumClassRef :: Nil, EmptyValDef,
117+
def creator = New(Template(emptyConstructor, enumClassRef :: Nil, Nil, EmptyValDef,
118118
List(enumTagDef, toStringDef) ++ registerCall))
119119
DefDef(nme.DOLLAR_NEW, Nil,
120120
List(List(param(nme.tag, defn.IntType), param(nme.name, defn.StringType))),
@@ -215,7 +215,7 @@ object DesugarEnums {
215215
if (!enumClass.exists) EmptyTree
216216
else if (enumClass.typeParams.nonEmpty) {
217217
val parent = interpolatedEnumParent(pos)
218-
val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, Nil)
218+
val impl = Template(emptyConstructor, parent :: Nil, Nil, EmptyValDef, Nil)
219219
expandEnumModule(name, impl, mods, pos)
220220
}
221221
else {

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -753,16 +753,24 @@ object Trees {
753753
def isClassDef: Boolean = rhs.isInstanceOf[Template[_]]
754754
}
755755

756-
/** extends parents { self => body } */
757-
case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList)
756+
/** extends parents { self => body }
757+
* @param parentsOrDerived A list of parents followed by a list of derived classes,
758+
* if this is of class untpd.DerivingTemplate.
759+
* Typed templates only have parents.
760+
*/
761+
case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parentsOrDerived: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList)
758762
extends DefTree[T] with WithLazyField[List[Tree[T]]] {
759763
type ThisTree[-T >: Untyped] = Template[T]
760764
def unforcedBody: LazyTreeList = unforced
761765
def unforced: LazyTreeList = preBody
762766
protected def force(x: AnyRef): Unit = preBody = x
763767
def body(implicit ctx: Context): List[Tree[T]] = forceIfLazy
768+
769+
def parents: List[Tree[T]] = parentsOrDerived // overridden by DerivingTemplate
770+
def derived: List[untpd.Tree] = Nil // overridden by DerivingTemplate
764771
}
765772

773+
766774
/** import expr.selectors
767775
* where a selector is either an untyped `Ident`, `name` or
768776
* an untyped thicket consisting of `name` and `rename`.
@@ -1147,9 +1155,9 @@ object Trees {
11471155
case tree: TypeDef if (name == tree.name) && (rhs eq tree.rhs) => tree
11481156
case _ => finalize(tree, untpd.TypeDef(name, rhs))
11491157
}
1150-
def Template(tree: Tree)(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList): Template = tree match {
1151-
case tree: Template if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.unforcedBody) => tree
1152-
case _ => finalize(tree, untpd.Template(constr, parents, self, body))
1158+
def Template(tree: Tree)(constr: DefDef, parents: List[Tree], derived: List[untpd.Tree], self: ValDef, body: LazyTreeList): Template = tree match {
1159+
case tree: Template if (constr eq tree.constr) && (parents eq tree.parents) && (derived eq tree.derived) && (self eq tree.self) && (body eq tree.unforcedBody) => tree
1160+
case tree => finalize(tree, untpd.Template(constr, parents, derived, self, body))
11531161
}
11541162
def Import(tree: Tree)(expr: Tree, selectors: List[untpd.Tree]): Import = tree match {
11551163
case tree: Import if (expr eq tree.expr) && (selectors eq tree.selectors) => tree
@@ -1186,8 +1194,8 @@ object Trees {
11861194
DefDef(tree: Tree)(name, tparams, vparamss, tpt, rhs)
11871195
def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs): TypeDef =
11881196
TypeDef(tree: Tree)(name, rhs)
1189-
def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody): Template =
1190-
Template(tree: Tree)(constr, parents, self, body)
1197+
def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody): Template =
1198+
Template(tree: Tree)(constr, parents, derived, self, body)
11911199
}
11921200

11931201
/** Hook to indicate that a transform of some subtree should be skipped */
@@ -1294,8 +1302,8 @@ object Trees {
12941302
case tree @ TypeDef(name, rhs) =>
12951303
implicit val ctx = localCtx
12961304
cpy.TypeDef(tree)(name, transform(rhs))
1297-
case tree @ Template(constr, parents, self, _) =>
1298-
cpy.Template(tree)(transformSub(constr), transform(parents), transformSub(self), transformStats(tree.body))
1305+
case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty =>
1306+
cpy.Template(tree)(transformSub(constr), transform(tree.parents), Nil, transformSub(self), transformStats(tree.body))
12991307
case Import(expr, selectors) =>
13001308
cpy.Import(tree)(transform(expr), selectors)
13011309
case PackageDef(pid, stats) =>
@@ -1416,7 +1424,7 @@ object Trees {
14161424
case TypeDef(name, rhs) =>
14171425
implicit val ctx = localCtx
14181426
this(x, rhs)
1419-
case tree @ Template(constr, parents, self, _) =>
1427+
case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty =>
14201428
this(this(this(this(x, constr), parents), self), tree.body)
14211429
case Import(expr, selectors) =>
14221430
this(x, expr)

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
293293
val findLocalDummy = new FindLocalDummyAccumulator(cls)
294294
val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy.apply)
295295
.orElse(ctx.newLocalDummy(cls))
296-
val impl = untpd.Template(constr, parents, selfType, newTypeParams ++ body)
296+
val impl = untpd.Template(constr, parents, Nil, selfType, newTypeParams ++ body)
297297
.withType(localDummy.termRef)
298298
ta.assignType(untpd.TypeDef(cls.name, impl), cls)
299299
}

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
3939
def withName(name: Name)(implicit ctx: Context): ModuleDef = cpy.ModuleDef(this)(name.toTermName, impl)
4040
}
4141

42+
/** An untyped template with a derives clause. Derived parents are added to the end
43+
* of the `parents` list. `derivedCount` keeps track of how many there are.
44+
* This representation was chosen because it balances two concerns:
45+
* - maximize overlap between DerivingTemplate and Template for code streamlining
46+
* - keep invariant that elements of untyped trees align with source positions
47+
*/
48+
class DerivingTemplate(constr: DefDef, parentsOrDerived: List[Tree], self: ValDef, preBody: LazyTreeList, derivedCount: Int)
49+
extends Template(constr, parentsOrDerived, self, preBody) {
50+
override val parents = parentsOrDerived.dropRight(derivedCount)
51+
override val derived = parentsOrDerived.takeRight(derivedCount)
52+
}
53+
4254
case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree
4355

4456
case class SymbolLit(str: String) extends TermTree
@@ -299,7 +311,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
299311
def ValDef(name: TermName, tpt: Tree, rhs: LazyTree): ValDef = new ValDef(name, tpt, rhs)
300312
def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs)
301313
def TypeDef(name: TypeName, rhs: Tree): TypeDef = new TypeDef(name, rhs)
302-
def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList): Template = new Template(constr, parents, self, body)
314+
def Template(constr: DefDef, parents: List[Tree], derived: List[Tree], self: ValDef, body: LazyTreeList): Template =
315+
if (derived.isEmpty) new Template(constr, parents, self, body)
316+
else new DerivingTemplate(constr, parents ++ derived, self, body, derived.length)
303317
def Import(expr: Tree, selectors: List[Tree]): Import = new Import(expr, selectors)
304318
def PackageDef(pid: RefTree, stats: List[Tree]): PackageDef = new PackageDef(pid, stats)
305319
def Annotated(arg: Tree, annot: Tree): Annotated = new Annotated(arg, annot)
@@ -425,8 +439,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
425439
case _ => finalize(tree, untpd.ModuleDef(name, impl))
426440
}
427441
def ParsedTry(tree: Tree)(expr: Tree, handler: Tree, finalizer: Tree): TermTree = tree match {
428-
case tree: ParsedTry
429-
if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree
442+
case tree: ParsedTry if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree
430443
case _ => finalize(tree, untpd.ParsedTry(expr, handler, finalizer))
431444
}
432445
def SymbolLit(tree: Tree)(str: String): TermTree = tree match {
@@ -507,6 +520,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
507520
override def transformMoreCases(tree: Tree)(implicit ctx: Context): Tree = tree match {
508521
case ModuleDef(name, impl) =>
509522
cpy.ModuleDef(tree)(name, transformSub(impl))
523+
case tree: DerivingTemplate =>
524+
cpy.Template(tree)(transformSub(tree.constr), transform(tree.parents), transform(tree.derived), transformSub(tree.self), transformStats(tree.body))
510525
case ParsedTry(expr, handler, finalizer) =>
511526
cpy.ParsedTry(tree)(transform(expr), transform(handler), transform(finalizer))
512527
case SymbolLit(str) =>
@@ -554,6 +569,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
554569
override def foldMoreCases(x: X, tree: Tree)(implicit ctx: Context): X = tree match {
555570
case ModuleDef(name, impl) =>
556571
this(x, impl)
572+
case tree: DerivingTemplate =>
573+
this(this(this(this(this(x, tree.constr), tree.parents), tree.derived), tree.self), tree.body)
557574
case ParsedTry(expr, handler, finalizer) =>
558575
this(this(this(x, expr), handler), finalizer)
559576
case SymbolLit(str) =>

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ class TreeUnpickler(reader: TastyReader,
908908
tparams ++ vparams ++ stats
909909
})
910910
setPos(start,
911-
untpd.Template(constr, mappedParents, self, lazyStats)
911+
untpd.Template(constr, mappedParents, Nil, self, lazyStats)
912912
.withType(localDummy.termRef))
913913
}
914914

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
10571057
val parents = times(readNat(), () => readTreeRef())
10581058
val self = readValDefRef()
10591059
val body = until(end, () => readTreeRef())
1060-
untpd.Template(???, parents, self, body) // !!! TODO: pull out primary constructor
1060+
untpd.Template(???, parents, Nil, self, body) // !!! TODO: pull out primary constructor
10611061
.withType(symbol.namedType)
10621062

10631063
case BLOCKtree =>

compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ object JavaParsers {
125125
stats1 = constr1 :: stats1
126126
constr1 = makeConstructor(List(scalaDot(tpnme.Unit)), tparams, Flags.JavaDefined | Flags.PrivateLocal)
127127
}
128-
Template(constr1.asInstanceOf[DefDef], parents, EmptyValDef, stats1)
128+
Template(constr1.asInstanceOf[DefDef], parents, Nil, EmptyValDef, stats1)
129129
}
130130

131131
def makeSyntheticParam(count: Int, tpt: Tree): ValDef =
@@ -623,8 +623,8 @@ object JavaParsers {
623623
else {
624624
val template = cdef.rhs.asInstanceOf[Template]
625625
cpy.TypeDef(cdef)(cdef.name,
626-
cpy.Template(template)(template.constr, template.parents, template.self,
627-
importCompanionObject(cdef) :: template.body)).withMods(cdef.mods)
626+
cpy.Template(template)(body = importCompanionObject(cdef) :: template.body))
627+
.withMods(cdef.mods)
628628
}
629629

630630
List(makeCompanionObject(cdefNew, statics), cdefNew)

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -642,8 +642,7 @@ object Parsers {
642642

643643
/** QualId ::= id {`.' id}
644644
*/
645-
val qualId: () => Tree =
646-
() => dotSelectors(termIdent())
645+
def qualId(): Tree = dotSelectors(termIdent())
647646

648647
/** SimpleExpr ::= literal
649648
* | symbol
@@ -1489,7 +1488,7 @@ object Parsers {
14891488
case parent :: Nil if in.token != LBRACE =>
14901489
reposition(if (parent.isType) ensureApplied(wrapNew(parent)) else parent)
14911490
case _ =>
1492-
New(reposition(templateBodyOpt(emptyConstructor, parents, isEnum = false)))
1491+
New(reposition(templateBodyOpt(emptyConstructor, parents, Nil, isEnum = false)))
14931492
}
14941493
}
14951494

@@ -2453,7 +2452,7 @@ object Parsers {
24532452
tokenSeparated(WITH, constrApp)
24542453
}
24552454
else Nil
2456-
Template(constr, parents, EmptyValDef, Nil)
2455+
Template(constr, parents, Nil, EmptyValDef, Nil)
24572456
}
24582457

24592458
/* -------- TEMPLATES ------------------------------------------- */
@@ -2501,7 +2500,7 @@ object Parsers {
25012500
val derived =
25022501
if (isIdent(nme.derives)) {
25032502
in.nextToken()
2504-
tokenSeparated(COMMA, qualId)
2503+
tokenSeparated(COMMA, () => convertToTypeId(qualId()))
25052504
}
25062505
else Nil
25072506
(extended, derived)
@@ -2510,11 +2509,11 @@ object Parsers {
25102509
/** Template ::= InheritClauses [TemplateBody]
25112510
*/
25122511
def template(constr: DefDef, isEnum: Boolean = false): Template = {
2513-
val (parents, deriveds) = inheritClauses()
2512+
val (parents, derived) = inheritClauses()
25142513
newLineOptWhenFollowedBy(LBRACE)
25152514
if (isEnum && in.token != LBRACE)
25162515
syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token))
2517-
templateBodyOpt(constr, parents, isEnum)
2516+
templateBodyOpt(constr, parents, derived, isEnum)
25182517
}
25192518

25202519
/** TemplateOpt = [Template]
@@ -2524,15 +2523,15 @@ object Parsers {
25242523
if (in.token == EXTENDS || isIdent(nme.derives) || in.token == LBRACE)
25252524
template(constr, isEnum)
25262525
else
2527-
Template(constr, Nil, EmptyValDef, Nil)
2526+
Template(constr, Nil, Nil, EmptyValDef, Nil)
25282527
}
25292528

25302529
/** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
25312530
*/
2532-
def templateBodyOpt(constr: DefDef, parents: List[Tree], isEnum: Boolean): Template = {
2531+
def templateBodyOpt(constr: DefDef, parents: List[Tree], derived: List[Tree], isEnum: Boolean): Template = {
25332532
val (self, stats) =
25342533
if (in.token == LBRACE) withinEnum(isEnum)(templateBody()) else (EmptyValDef, Nil)
2535-
Template(constr, parents, self, stats)
2534+
Template(constr, parents, derived, self, stats)
25362535
}
25372536

25382537
def templateBody(): (ValDef, List[Tree]) = {

compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class DecompilerPrinter(_ctx: Context) extends RefinedPrinter(_ctx) {
6969
val bodyText = " {" ~~ toTextGlobal(impl.body, "\n") ~ "}"
7070
parentsText.provided(parents.nonEmpty) ~ bodyText
7171
}
72-
else super.toTextTemplate(impl.copy(parents = parents, preBody = body), ofNew)
72+
else super.toTextTemplate(impl.copy(parentsOrDerived = parents, preBody = body), ofNew)
7373
}
7474

7575
override protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text = {

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
686686
}
687687

688688
protected def toTextTemplate(impl: Template, ofNew: Boolean = false): Text = {
689-
val Template(constr @ DefDef(_, tparams, vparamss, _, _), parents, self, _) = impl
689+
val Template(constr @ DefDef(_, tparams, vparamss, _, _), _, self, _) = impl
690690
val tparamsTxt = withEnclosingDef(constr) { tparamsText(tparams) }
691691
val primaryConstrs = if (constr.rhs.isEmpty) Nil else constr :: Nil
692692
val prefix: Text =
@@ -697,7 +697,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
697697
if (constr.mods.hasAnnotations && !constr.mods.hasFlags) modsText = modsText ~~ " this"
698698
withEnclosingDef(constr) { addVparamssText(tparamsTxt ~~ modsText, vparamss) }
699699
}
700-
val parentsText = Text(parents map constrText, keywordStr(" with "))
700+
val parentsText = Text(impl.parents.map(constrText), if (ofNew) keywordStr(" with ") else ", ")
701+
val derivedText = Text(impl.derived.map(toText(_)), ", ")
701702
val selfText = {
702703
val selfName = if (self.name == nme.WILDCARD) keywordStr("this") else self.name.toString
703704
(selfName ~ optText(self.tpt)(": " ~ _) ~ " =>").close
@@ -715,7 +716,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
715716

716717
val bodyText = " {" ~~ selfText ~~ toTextGlobal(primaryConstrs ::: body, "\n") ~ "}"
717718

718-
prefix ~ keywordText(" extends").provided(!ofNew && parents.nonEmpty) ~~ parentsText ~ bodyText
719+
prefix ~
720+
keywordText(" extends").provided(!ofNew && impl.parents.nonEmpty) ~~ parentsText ~
721+
keywordText(" derives").provided(impl.derived.nonEmpty) ~~ derivedText ~
722+
bodyText
719723
}
720724

721725
protected def templateText(tree: TypeDef, impl: Template): Text = {

0 commit comments

Comments
 (0)