Skip to content

Commit 0aaa87d

Browse files
committed
Port validateBaseTypes from Scala 2
1 parent 16a1553 commit 0aaa87d

File tree

2 files changed

+43
-24
lines changed

2 files changed

+43
-24
lines changed

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -782,34 +782,53 @@ object RefChecks {
782782
report.error(problem(), clazz.srcPos)
783783
}
784784

785-
// check that basetype and subtype agree on types of trait parameters
785+
// Checks base types of the current clazz against each other
786786
//
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)
808827
}
809828
}
810829

811830
checkParameterizedTraitsOK()
812-
checkTraitParametersOK()
831+
validateBaseTypes()
813832
}
814833

815834
/** Check that `site` does not inherit conflicting generic instances of `baseCls`,

tests/neg/i3989f.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ object Test extends App {
33
class B[+X](val y: X) extends A[X](y)
44
class C extends B(5) with A[String] // error: illegal inheritance
55

6-
class D extends B(5) with A[Any] // error: illegal parameter
6+
class D extends B(5) with A[Any] // ok
77

88
def f(a: A[Int]): String = a match {
99
case c: C => c.x

0 commit comments

Comments
 (0)