@@ -495,7 +495,27 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
495
495
sym.setFlag(Scala2x )
496
496
if (! (isRefinementClass(sym) || isUnpickleRoot(sym) || sym.is(Scala2Existential ))) {
497
497
val owner = sym.owner
498
- if (owner.isClass)
498
+ val canEnter =
499
+ owner.isClass &&
500
+ (! sym.is(TypeParam ) ||
501
+ owner.infoOrCompleter.match
502
+ case completer : ClassUnpickler =>
503
+ // Type parameters seen after class initialization are not
504
+ // actually type parameters of the current class but of some
505
+ // external class because of the bizarre way in which Scala 2
506
+ // pickles them (see
507
+ // https://github.com/scala/scala/blob/aa31e3e6bb945f5d69740d379ede1cd514904109/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala#L181-L197).
508
+ // Make sure we don't enter them in the class otherwise the
509
+ // compiler will get very confused (testcase in sbt-test/scala2-compat/i12641).
510
+ // Note: I don't actually know if these stray type parameters
511
+ // can also show up before initialization, if that's the case
512
+ // we'll need to study more closely how Scala 2 handles type
513
+ // parameter unpickling and try to emulate it.
514
+ ! completer.isInitialized
515
+ case _ =>
516
+ true )
517
+
518
+ if (canEnter)
499
519
owner.asClass.enter(sym, symScope(owner))
500
520
}
501
521
sym
@@ -625,23 +645,30 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
625
645
object localMemberUnpickler extends LocalUnpickler
626
646
627
647
class ClassUnpickler (infoRef : Int ) extends LocalUnpickler with TypeParamsCompleter {
628
- private def readTypeParams ()(using Context ): List [TypeSymbol ] = {
648
+ private var myTypeParams : List [TypeSymbol ] = null
649
+
650
+ private def readTypeParams ()(using Context ): Unit = {
629
651
val tag = readByte()
630
652
val end = readNat() + readIndex
631
- if (tag == POLYtpe ) {
632
- val unusedRestpeRef = readNat()
633
- until(end, () => readSymbolRef()( using ctx)). asInstanceOf [ List [ TypeSymbol ]]
634
- }
635
- else Nil
653
+ myTypeParams =
654
+ if (tag == POLYtpe ) {
655
+ val unusedRestpeRef = readNat()
656
+ until(end, () => readSymbolRef()( using ctx)). asInstanceOf [ List [ TypeSymbol ]]
657
+ } else Nil
636
658
}
637
- private def loadTypeParams (using Context ) =
659
+ private def loadTypeParams ()( using Context ) =
638
660
atReadPos(index(infoRef), () => readTypeParams()(using ctx))
639
661
662
+ /** Have the type params of this class already been unpickled? */
663
+ def isInitialized : Boolean = myTypeParams ne null
664
+
640
665
/** Force reading type params early, we need them in setClassInfo of subclasses. */
641
- def init ()(using Context ): List [TypeSymbol ] = loadTypeParams
666
+ def init ()(using Context ): List [TypeSymbol ] =
667
+ if ! isInitialized then loadTypeParams()
668
+ myTypeParams
642
669
643
670
override def completerTypeParams (sym : Symbol )(using Context ): List [TypeSymbol ] =
644
- loadTypeParams
671
+ init()
645
672
}
646
673
647
674
def rootClassUnpickler (start : Coord , cls : Symbol , module : Symbol , infoRef : Int ): ClassUnpickler =
0 commit comments