@@ -647,21 +647,11 @@ object RefChecks {
647647 */
648648 def checkCaseClassInheritanceInvariant () = {
649649 for (caseCls <- clazz.info.baseClasses.tail.find(_.is(Case )))
650- for (bc <- caseCls.info.baseClasses.tail)
651- if (bc.typeParams.exists(_.paramVariance != 0 )) {
652- val caseBT = self.baseType(caseCls)
653- val thisBT = self.baseType(bc)
654- val combinedBT = caseBT.baseType(bc)
655- if (! (thisBT =:= combinedBT))
656- ctx.errorOrMigrationWarning(
657- em """ illegal inheritance: $clazz inherits case $caseCls
658- |but the two have different base type instances for $bc.
659- |
660- | Basetype for $clazz: $thisBT
661- | Basetype via $caseCls: $combinedBT""" , clazz.pos)
662- }
650+ for (baseCls <- caseCls.info.baseClasses.tail)
651+ if (baseCls.typeParams.exists(_.paramVariance != 0 ))
652+ for (problem <- variantInheritanceProblems(baseCls, caseCls, " non-variant" , " case " ))
653+ ctx.errorOrMigrationWarning(problem(), clazz.pos)
663654 }
664-
665655 checkNoAbstractMembers()
666656 if (abstractErrors.isEmpty)
667657 checkNoAbstractDecls(clazz)
@@ -684,6 +674,51 @@ object RefChecks {
684674 }
685675 }
686676
677+ if (! clazz.is(Trait )) {
678+ // check that parameterized base classes and traits are typed in the same way as from the superclass
679+ // I.e. say we have
680+ //
681+ // Sub extends Super extends* Base
682+ //
683+ // where `Base` has value parameters. Enforce that
684+ //
685+ // Sub.thisType.baseType(Base) =:= Sub.thisType.baseType(Super).baseType(Base)
686+ //
687+ // This is necessary because parameter values are determined directly or indirectly
688+ // by `Super`. So we cannot pretend they have a different type when seen from `Sub`.
689+ def checkParameterizedTraitsOK () = {
690+ val mixins = clazz.mixins
691+ for {
692+ cls <- clazz.info.baseClasses.tail
693+ if cls.paramAccessors.nonEmpty && ! mixins.contains(cls)
694+ problem <- variantInheritanceProblems(cls, clazz.asClass.superClass, " parameterized" , " super" )
695+ } ctx.error(problem(), clazz.pos)
696+ }
697+
698+ checkParameterizedTraitsOK()
699+ }
700+
701+ /** Check that `site` does not inherit conflicting generic instances of `baseCls`,
702+ * when doing a direct base type or going via intermediate class `middle`. I.e, we require:
703+ *
704+ * site.baseType(baseCls) =:= site.baseType(middle).baseType(baseCls)
705+ *
706+ * Return an optional by name error message if this test fails.
707+ */
708+ def variantInheritanceProblems (
709+ baseCls : Symbol , middle : Symbol , baseStr : String , middleStr : String ): Option [() => String ] = {
710+ val superBT = self.baseType(middle)
711+ val thisBT = self.baseType(baseCls)
712+ val combinedBT = superBT.baseType(baseCls)
713+ if (combinedBT =:= thisBT) None // ok
714+ else
715+ Some (() =>
716+ em """ illegal inheritance: $clazz inherits conflicting instances of $baseStr base $baseCls.
717+ |
718+ | Direct basetype: $thisBT
719+ | Basetype via $middleStr$middle: $combinedBT""" )
720+ }
721+
687722 /* Returns whether there is a symbol declared in class `inclazz`
688723 * (which must be different from `clazz`) whose name and type
689724 * seen as a member of `class.thisType` matches `member`'s.
0 commit comments