@@ -782,34 +782,53 @@ object RefChecks {
782
782
report.error(problem(), clazz.srcPos)
783
783
}
784
784
785
- // check that basetype and subtype agree on types of trait parameters
785
+ // Checks base types of the current clazz against each other
786
786
//
787
- // I.e. trait and class parameters not only need to conform to the expected
788
- // type of the corresponding base-trait, but also to the type as seen by the
789
- // inheriting subtype.
790
- def checkTraitParametersOK () = for {
791
- parent <- clazz.info.parents
792
- parentSym = parent.classSymbol
793
- if parentSym.isClass
794
- cls = parentSym.asClass
795
- if cls.paramAccessors.nonEmpty
796
- param <- cls.paramAccessors
797
- } {
798
- val tpeFromParent = parent.memberInfo(param)
799
- val tpeFromClazz = clazz.thisType.memberInfo(param)
800
- if (! (tpeFromParent <:< tpeFromClazz)) {
801
- val msg =
802
- em """ illegal parameter: The types of $param do not match.
803
- |
804
- | $param in $cls has type: $tpeFromParent
805
- | but $clazz expects $param to have type: $tpeFromClazz"""
806
-
807
- report.error(msg, clazz.srcPos)
787
+ // In particular, it checks that there are no two base classes with
788
+ // different type instantiations.
789
+ //
790
+ // ported from Scala 2:
791
+ // https://github.com/scala/scala/blob/9bb659e62a9239c01aec14c171f8598bb1a576fe/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala#L834-L883
792
+ def validateBaseTypes (): Unit = {
793
+ val tpe = clazz.thisType // in Scala 2 this was clazz.tpe
794
+ val seenParents = mutable.HashSet [Type ]()
795
+ val baseClasses : List [ClassSymbol ] = clazz.info.baseClasses
796
+
797
+ // tracks types that we have seen for a particular base class in baseClasses
798
+ val seenTypes = mutable.Map .empty[Symbol , List [Type ]]
799
+
800
+ // validate all base types of a class in reverse linear order.
801
+ def register (tp : Type ): Unit = {
802
+ val baseClass = tp.typeSymbol
803
+ if (baseClasses contains baseClass) {
804
+ val alreadySeen = seenTypes.getOrElse(baseClass, Nil )
805
+ if (alreadySeen.forall { tp1 => ! (tp1 <:< tp) })
806
+ seenTypes.update(baseClass, tp :: alreadySeen.filter { tp1 => ! (tp <:< tp1) })
807
+ }
808
+ val remaining = tp.parents filterNot seenParents
809
+ seenParents ++= remaining
810
+ remaining foreach register
811
+ }
812
+ register(tpe)
813
+
814
+ seenTypes.foreach {
815
+ case (cls, Nil ) =>
816
+ assert(false ) // this case should not be reachable
817
+ case (cls, _ :: Nil ) =>
818
+ () // Ok
819
+ case (cls, tp1 :: tp2 :: _) =>
820
+ val msg =
821
+ em """ illegal inheritance;
822
+ |
823
+ | $clazz inherits different type instances of $cls:
824
+ | $tp1 and $tp2"""
825
+
826
+ report.error(msg, clazz.srcPos)
808
827
}
809
828
}
810
829
811
830
checkParameterizedTraitsOK()
812
- checkTraitParametersOK ()
831
+ validateBaseTypes ()
813
832
}
814
833
815
834
/** Check that `site` does not inherit conflicting generic instances of `baseCls`,
0 commit comments