@@ -484,46 +484,91 @@ class Namer { typer: Typer =>
484
484
/** Create top-level symbols for statements and enter them into symbol table */
485
485
def index (stats : List [Tree ])(implicit ctx : Context ): Context = {
486
486
487
- val classDef = mutable.Map [TypeName , TypeDef ]()
488
- val moduleDef = mutable.Map [TypeName , TypeDef ]()
487
+ // module name -> (stat, moduleCls | moduleVal)
488
+ val moduleClsDef = mutable.Map [TypeName , (Tree , TypeDef )]()
489
+ val moduleValDef = mutable.Map [TermName , (Tree , ValDef )]()
490
+
491
+ /** Remove the subtree `tree` from the expanded tree of `mdef` */
492
+ def removeInExpanded (mdef : Tree , tree : Tree ): Unit = {
493
+ val Thicket (trees) = expanded(mdef)
494
+ mdef.putAttachment(ExpandedTree , Thicket (trees.filter(_ != tree)))
495
+ }
496
+
497
+ /** Merge the module class `modCls` in the expanded tree of `mdef` with the given stats */
498
+ def mergeModuleClass (mdef : Tree , modCls : TypeDef , stats : List [Tree ]): TypeDef = {
499
+ var res : TypeDef = null
500
+ val Thicket (trees) = expanded(mdef)
501
+ val merged = trees.map { tree =>
502
+ if (tree == modCls) {
503
+ val impl = modCls.rhs.asInstanceOf [Template ]
504
+ res = cpy.TypeDef (modCls)(rhs = cpy.Template (impl)(body = stats ++ impl.body))
505
+ res
506
+ }
507
+ else tree
508
+ }
509
+
510
+ mdef.putAttachment(ExpandedTree , Thicket (merged))
511
+
512
+ res
513
+ }
514
+
515
+ /** Merge `fromCls` of `fromStat` into `toCls` of `toStat`
516
+ * if the former is synthetic and the latter not.
517
+ *
518
+ * Note:
519
+ * 1. `fromStat` and `toStat` could be the same stat
520
+ * 2. `fromCls` and `toCls` are necessarily different
521
+ */
522
+ def mergeIfSynthetic (fromStat : Tree , fromCls : TypeDef , toStat : Tree , toCls : TypeDef ): Unit =
523
+ if (fromCls.mods.is(Synthetic ) && ! toCls.mods.is(Synthetic )) {
524
+ removeInExpanded(fromStat, fromCls)
525
+ val mcls = mergeModuleClass(toStat, toCls, fromCls.rhs.asInstanceOf [Template ].body)
526
+ moduleClsDef(fromCls.name) = (toStat, mcls)
527
+ }
489
528
490
529
/** Merge the definitions of a synthetic companion generated by a case class
491
530
* and the real companion, if both exist.
492
531
*/
493
532
def mergeCompanionDefs () = {
494
- for (cdef @ TypeDef (name, _) <- stats)
495
- if (cdef.isClassDef) {
496
- classDef(name) = cdef
497
- cdef.attachmentOrElse(ExpandedTree , cdef) match {
498
- case Thicket (cls :: mval :: (mcls @ TypeDef (mname, _ : Template )) :: crest)
499
- if name.moduleClassName == mname =>
500
- moduleDef(name) = mcls
501
- case _ =>
502
- }
503
- }
504
- for (mdef @ ModuleDef (name, _) <- stats if ! mdef.mods.is(Flags .Package )) {
505
- val typName = name.toTypeName
506
- // Expansion of object is a flattened thicket with the first two elements being:
507
- // module val :: module class :: rest
508
- val Thicket (vdef :: (mcls @ TypeDef (_, impl : Template )) :: rest) = expanded(mdef)
509
- moduleDef(typName) = mcls
510
- classDef get name.toTypeName match {
511
- case Some (cdef) =>
512
- cdef.attachmentOrElse(ExpandedTree , cdef) match {
513
- case Thicket (cls :: mval :: TypeDef (mname, compimpl : Template ) :: crest)
514
- if name.moduleClassName == mname =>
515
- val mcls1 = cpy.TypeDef (mcls)(
516
- rhs = cpy.Template (impl)(body = compimpl.body ++ impl.body))
517
- mdef.putAttachment(ExpandedTree , Thicket (vdef :: mcls1 :: rest))
518
- moduleDef(typName) = mcls1
519
- cdef.putAttachment(ExpandedTree , Thicket (cls :: crest))
533
+ def valid (mdef : MemberDef ): Boolean = mdef.mods.is(Module , butNot = Package )
534
+
535
+ for (stat <- stats)
536
+ expanded(stat) match {
537
+ case Thicket (trees) => // companion object always expands to thickets
538
+ trees.map {
539
+ case mcls @ TypeDef (name, impl : Template ) if valid(mcls) =>
540
+ moduleClsDef.get(name) match {
541
+ case Some ((stat1, mcls1@ TypeDef (_, impl1 : Template ))) =>
542
+ mergeIfSynthetic(stat, mcls, stat1, mcls1)
543
+ mergeIfSynthetic(stat1, mcls1, stat, mcls)
544
+ case None =>
545
+ moduleClsDef(name) = (stat, mcls)
546
+ }
547
+
548
+ case vdef @ ValDef (name, _, _) if valid(vdef) =>
549
+ moduleValDef.get(name) match {
550
+ case Some ((stat1, vdef1)) =>
551
+ if (vdef.mods.is(Synthetic ) && ! vdef1.mods.is(Synthetic ))
552
+ removeInExpanded(stat, vdef)
553
+ else if (! vdef.mods.is(Synthetic ) && vdef1.mods.is(Synthetic )) {
554
+ removeInExpanded(stat1, vdef1)
555
+ moduleValDef(name) = (stat, vdef)
556
+ }
557
+ else {
558
+ // double definition of objects or case classes, handled elsewhere
559
+ }
560
+ case None =>
561
+ moduleValDef(name) = (stat, vdef)
562
+ }
563
+
520
564
case _ =>
521
565
}
522
- case none =>
566
+ case _ =>
567
+
523
568
}
524
- }
525
569
}
526
570
571
+ /** Create links between companion object and companion class */
527
572
def createLinks (classTree : TypeDef , moduleTree : TypeDef )(implicit ctx : Context ) = {
528
573
val claz = ctx.denotNamed(classTree.name.encode).symbol
529
574
val modl = ctx.denotNamed(moduleTree.name.encode).symbol
@@ -532,8 +577,29 @@ class Namer { typer: Typer =>
532
577
}
533
578
534
579
def createCompanionLinks (implicit ctx : Context ): Unit = {
580
+ val classDef = mutable.Map [TypeName , TypeDef ]()
581
+ val moduleDef = mutable.Map [TypeName , TypeDef ]()
582
+
583
+ def updateCache (cdef : TypeDef ): Unit = {
584
+ if (! cdef.isClassDef || cdef.mods.is(Package )) return
585
+
586
+ if (cdef.mods.is(ModuleClass )) moduleDef(cdef.name) = cdef
587
+ else classDef(cdef.name) = cdef
588
+ }
589
+
590
+ for (stat <- stats)
591
+ expanded(stat) match {
592
+ case cdef : TypeDef => updateCache(cdef)
593
+ case Thicket (trees) =>
594
+ trees.map {
595
+ case cdef : TypeDef => updateCache(cdef)
596
+ case _ =>
597
+ }
598
+ case _ =>
599
+ }
600
+
535
601
for (cdef @ TypeDef (name, _) <- classDef.values) {
536
- moduleDef.getOrElse(name, EmptyTree ) match {
602
+ moduleDef.getOrElse(name.moduleClassName , EmptyTree ) match {
537
603
case t : TypeDef =>
538
604
createLinks(cdef, t)
539
605
case EmptyTree =>
0 commit comments