@@ -377,13 +377,13 @@ class Namer { typer: Typer =>
377
377
/** Expand tree and create top-level symbols for statement and enter them into symbol table */
378
378
def index (stat : Tree )(using Context ): Context = {
379
379
expand(stat)
380
- indexExpanded(stat)
380
+ indexExpanded(stat, mutable. Buffer .empty) // here we do not expect to populate the buffer
381
381
}
382
382
383
383
/** Create top-level symbols for all statements in the expansion of this statement and
384
384
* enter them into symbol table
385
385
*/
386
- def indexExpanded (origStat : Tree )(using Context ): Context = {
386
+ def indexExpanded (origStat : Tree , delayedEntry : mutable. Buffer [ Context ?=> Context ] )(using Context ): Context = {
387
387
def recur (stat : Tree ): Context = stat match {
388
388
case pcl : PackageDef =>
389
389
val pkg = createPackageSymbol(pcl.pid)
@@ -395,10 +395,23 @@ class Namer { typer: Typer =>
395
395
ctx.importContext(imp, createSymbol(imp))
396
396
case mdef : DefTree =>
397
397
val sym = createSymbol(mdef)
398
- enterSymbol(sym)
399
- setDocstring(sym, origStat)
400
- addEnumConstants(mdef, sym)
401
- ctx
398
+ def enterDefTree (sym : Symbol ): Context =
399
+ enterSymbol(sym)
400
+ setDocstring(sym, origStat)
401
+ addEnumConstants(mdef, sym)
402
+ ctx
403
+ if sym.is(Synthetic ) && isEnumOrdinal(sym) then
404
+ delayedEntry += { ctx ?=>
405
+ // Here we delay entering into scope of an enum ordinal method until after
406
+ // the parents of `sym.owner` are known. This is because it is illegal to override ordinal
407
+ // in java.lang.Enum
408
+ if ! clashingJavaEnumOrdinal(sym) then
409
+ enterDefTree(sym)
410
+ ctx
411
+ }
412
+ ctx
413
+ else
414
+ enterDefTree(sym)
402
415
case stats : Thicket =>
403
416
stats.toList.foreach(recur)
404
417
ctx
@@ -456,7 +469,10 @@ class Namer { typer: Typer =>
456
469
/** Create top-level symbols for statements and enter them into symbol table
457
470
* @return A context that reflects all imports in `stats`.
458
471
*/
459
- def index (stats : List [Tree ])(using Context ): Context = {
472
+ def index (stats : List [Tree ])(using Context ): Context =
473
+ index(stats, mutable.Buffer .empty) // here we do not expect to fill the buffer
474
+
475
+ def index (stats : List [Tree ], delayedEntry : mutable.Buffer [Context ?=> Context ])(using Context ): Context = {
460
476
461
477
// module name -> (stat, moduleCls | moduleVal)
462
478
val moduleClsDef = mutable.Map [TypeName , (Tree , TypeDef )]()
@@ -631,7 +647,7 @@ class Namer { typer: Typer =>
631
647
632
648
stats.foreach(expand)
633
649
mergeCompanionDefs()
634
- val ctxWithStats = stats.foldLeft(ctx)((ctx, stat) => indexExpanded(stat)(using ctx))
650
+ val ctxWithStats = stats.foldLeft(ctx)((ctx, stat) => indexExpanded(stat, delayedEntry )(using ctx))
635
651
createCompanionLinks(using ctxWithStats)
636
652
ctxWithStats
637
653
}
@@ -663,6 +679,23 @@ class Namer { typer: Typer =>
663
679
sym.resetFlag(GivenOrImplicit )
664
680
}
665
681
682
+ private def findMatch (denot : SymDenotation , owner : Symbol )(using Context ) =
683
+ owner.info.decls.lookupAll(denot.name).exists(alt =>
684
+ alt != denot.symbol && alt.info.matchesLoosely(denot.info))
685
+
686
+ private def isEnumOrdinal (denot : SymDenotation )(using Context ) =
687
+ denot.name == nme.ordinal
688
+ && denot.owner.isClass && denot.owner.isEnumClass
689
+
690
+ private def clashingJavaEnumOrdinal (denot : SymDenotation )(using Context ) =
691
+ def firstParentCls (owner : Symbol ) =
692
+ owner.asClass.classParents.head.classSymbol
693
+ def isJavaEnumBaseClass (owner : Symbol ) =
694
+ owner.isClass && owner.isEnumClass && owner.derivesFrom(defn.JavaEnumClass )
695
+ denot.name == nme.ordinal
696
+ && isJavaEnumBaseClass(denot.owner)
697
+ && findMatch(denot, firstParentCls(denot.owner))
698
+
666
699
/** The completer of a symbol defined by a member def or import (except ClassSymbols) */
667
700
class Completer (val original : Tree )(ictx : Context ) extends LazyType with SymbolLoaders .SecondCompleter {
668
701
@@ -755,22 +788,11 @@ class Namer { typer: Typer =>
755
788
if (owner.is(Module )) owner.linkedClass.is(CaseClass )
756
789
else owner.is(CaseClass )
757
790
}
758
- def isJavaEnumBaseClass (owner : Symbol ) =
759
- owner.isClass && owner.isEnumClass && owner.derivesFrom(defn.JavaEnumClass )
760
- def firstParentCls (owner : Symbol ) =
761
- owner.asClass.classParents.head.classSymbol
762
- def findMatch (owner : Symbol ) =
763
- owner.info.decls.lookupAll(denot.name).exists(alt =>
764
- alt != denot.symbol && alt.info.matchesLoosely(denot.info))
765
791
def clashingCaseClassMethod =
766
792
desugar.isRetractableCaseClassMethodName(denot.name)
767
793
&& isCaseClass(denot.owner)
768
- && findMatch(denot.owner)
769
- def clashingEnumMethod =
770
- denot.name == nme.ordinal
771
- && isJavaEnumBaseClass(denot.owner)
772
- && findMatch(firstParentCls(denot.owner))
773
- val isClashingSynthetic = denot.is(Synthetic ) && (clashingCaseClassMethod || clashingEnumMethod)
794
+ && findMatch(denot, denot.owner)
795
+ val isClashingSynthetic = denot.is(Synthetic ) && (clashingCaseClassMethod || clashingJavaEnumOrdinal(denot))
774
796
if (isClashingSynthetic) {
775
797
typr.println(i " invalidating clashing $denot in ${denot.owner}" )
776
798
denot.markAbsent()
@@ -936,6 +958,11 @@ class Namer { typer: Typer =>
936
958
/** info to be used temporarily while completing the class, to avoid cyclic references. */
937
959
private var tempInfo : TempClassInfo = _
938
960
961
+ /** indexing symbols that are delayed until after parents are known:
962
+ * - def ordinal: Int (if parent is not java.lang.Enum)
963
+ */
964
+ private var delayedEnter : List [Context ?=> Context ] = _
965
+
939
966
val TypeDef (name, impl @ Template (constr, _, self, _)) = original
940
967
941
968
private val (params, rest): (List [Tree ], List [Tree ]) = impl.body.span {
@@ -1096,8 +1123,11 @@ class Namer { typer: Typer =>
1096
1123
1097
1124
localCtx = completerCtx.inClassContext(selfInfo)
1098
1125
1126
+ val delayedEnterBuf = collection.mutable.ListBuffer .empty[Context ?=> Context ]
1127
+
1099
1128
index(constr)
1100
- index(rest)(using localCtx)
1129
+ index(rest, delayedEnterBuf)(using localCtx)
1130
+ delayedEnter = delayedEnterBuf.toList
1101
1131
1102
1132
symbolOfTree(constr).info.stripPoly match // Completes constr symbol as a side effect
1103
1133
case mt : MethodType if cls.is(Case ) && mt.isParamDependent =>
@@ -1202,6 +1232,10 @@ class Namer { typer: Typer =>
1202
1232
denot.info = tempInfo.finalized(parentTypes)
1203
1233
tempInfo = null // The temporary info can now be garbage-collected
1204
1234
1235
+ // now we know the parents we can decide if we enter the symbols or not
1236
+ delayedEnter.foldLeft(localCtx) { (localCtx, op) => op(using localCtx) }
1237
+ delayedEnter = null
1238
+
1205
1239
Checking .checkWellFormed(cls)
1206
1240
if (isDerivedValueClass(cls)) cls.setFlag(Final )
1207
1241
cls.info = avoidPrivateLeaks(cls)
0 commit comments