@@ -647,21 +647,11 @@ object RefChecks {
647
647
*/
648
648
def checkCaseClassInheritanceInvariant () = {
649
649
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)
663
654
}
664
-
665
655
checkNoAbstractMembers()
666
656
if (abstractErrors.isEmpty)
667
657
checkNoAbstractDecls(clazz)
@@ -684,6 +674,51 @@ object RefChecks {
684
674
}
685
675
}
686
676
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
+
687
722
/* Returns whether there is a symbol declared in class `inclazz`
688
723
* (which must be different from `clazz`) whose name and type
689
724
* seen as a member of `class.thisType` matches `member`'s.
0 commit comments