@@ -484,46 +484,86 @@ 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
+ }
489
514
490
515
/** Merge the definitions of a synthetic companion generated by a case class
491
516
* and the real companion, if both exist.
492
517
*/
493
518
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))
519
+ def valid (mdef : MemberDef ): Boolean = ! mdef.mods.is(Package ) && mdef.mods.is(Module )
520
+
521
+ for (stat <- stats)
522
+ expanded(stat) match {
523
+ case Thicket (trees) => // companion object always expands to thickets
524
+ trees.map {
525
+ case mcls @ TypeDef (name, impl : Template ) if valid(mcls) =>
526
+ if (moduleClsDef.contains(name)) {
527
+ val (stat1, mcls1 @ TypeDef (_, impl1 : Template )) = moduleClsDef(name)
528
+ if (mcls.mods.is(Synthetic ) && ! mcls1.mods.is(Synthetic )) { // merge synthetic into user-defined module
529
+ removeInExpanded(stat, mcls)
530
+ val mcls2 = mergeModuleClass(stat1, mcls1, impl.body)
531
+ moduleClsDef(name) = (stat1, mcls2)
532
+ }
533
+ else if (! mcls.mods.is(Synthetic ) && mcls1.mods.is(Synthetic )) {
534
+ removeInExpanded(stat1, mcls1)
535
+ val mcls2 = mergeModuleClass(stat, mcls, impl1.body)
536
+ moduleClsDef(name) = (stat, mcls2)
537
+ }
538
+ else {
539
+ // redefinition of objects or case classes, handled elsewhere
540
+ }
541
+ }
542
+ else moduleClsDef(name) = (stat, mcls)
543
+
544
+ case vdef @ ValDef (name, _, _) if valid(vdef) =>
545
+ if (moduleValDef.contains(name)) {
546
+ val (stat1, vdef1) = moduleValDef(name)
547
+ if (vdef.mods.is(Synthetic ) && ! vdef1.mods.is(Synthetic )) // merge synthetic into user-defined module
548
+ removeInExpanded(stat, vdef)
549
+ else if (! vdef.mods.is(Synthetic ) && vdef1.mods.is(Synthetic )) {
550
+ removeInExpanded(stat1, vdef1)
551
+ moduleValDef(name) = (stat, vdef)
552
+ }
553
+ else {
554
+ // redefinition of objects or case classes, handled elsewhere
555
+ }
556
+ }
557
+ else moduleValDef(name) = (stat, vdef)
558
+
520
559
case _ =>
521
560
}
522
- case none =>
561
+ case _ =>
562
+
523
563
}
524
- }
525
564
}
526
565
566
+ /** Create links between companion object and companion class */
527
567
def createLinks (classTree : TypeDef , moduleTree : TypeDef )(implicit ctx : Context ) = {
528
568
val claz = ctx.denotNamed(classTree.name.encode).symbol
529
569
val modl = ctx.denotNamed(moduleTree.name.encode).symbol
@@ -532,8 +572,29 @@ class Namer { typer: Typer =>
532
572
}
533
573
534
574
def createCompanionLinks (implicit ctx : Context ): Unit = {
575
+ val classDef = mutable.Map [TypeName , TypeDef ]()
576
+ val moduleDef = mutable.Map [TypeName , TypeDef ]()
577
+
578
+ def updateCache (cdef : TypeDef ): Unit = {
579
+ if (! cdef.isClassDef || cdef.mods.is(Package )) return
580
+
581
+ if (cdef.mods.is(ModuleClass )) moduleDef(cdef.name) = cdef
582
+ else classDef(cdef.name) = cdef
583
+ }
584
+
585
+ for (stat <- stats)
586
+ expanded(stat) match {
587
+ case cdef : TypeDef => updateCache(cdef)
588
+ case Thicket (trees) =>
589
+ trees.map {
590
+ case cdef : TypeDef => updateCache(cdef)
591
+ case _ =>
592
+ }
593
+ case _ =>
594
+ }
595
+
535
596
for (cdef @ TypeDef (name, _) <- classDef.values) {
536
- moduleDef.getOrElse(name, EmptyTree ) match {
597
+ moduleDef.getOrElse(name.moduleClassName , EmptyTree ) match {
537
598
case t : TypeDef =>
538
599
createLinks(cdef, t)
539
600
case EmptyTree =>
0 commit comments