Skip to content

Commit ac6a889

Browse files
committed
Handle differences in package vs package object in TypeComparer
With the changes in Typer, it is now possible that a type `T` that is a member of some package object `pobj` in a package `p` is seen once as `p.pobj.T` and then also as `p.T`. Type comparer has to make sure that these two types are seen as equivalent.
1 parent 006ae3c commit ac6a889

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,14 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
225225
def compareNamed(tp1: Type, tp2: NamedType): Boolean = {
226226
implicit val ctx: Context = this.ctx
227227
tp2.info match {
228-
case info2: TypeAlias => recur(tp1, info2.alias)
228+
case info2: TypeAlias =>
229+
recur(tp1, info2.alias) || tryPackagePrefix2(tp1, tp2)
229230
case _ => tp1 match {
230231
case tp1: NamedType =>
231232
tp1.info match {
232233
case info1: TypeAlias =>
233234
if (recur(info1.alias, tp2)) return true
234-
if (tp1.prefix.isStable) return false
235+
if (tp1.prefix.isStable) return tryPackagePrefix1(tp1, tp2)
235236
// If tp1.prefix is stable, the alias does contain all information about the original ref, so
236237
// there's no need to try something else. (This is important for performance).
237238
// To see why we cannot in general stop here, consider:
@@ -253,7 +254,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
253254
if ((sym1 ne NoSymbol) && (sym1 eq sym2))
254255
ctx.erasedTypes ||
255256
sym1.isStaticOwner ||
256-
isSubType(tp1.prefix, tp2.prefix) ||
257+
isSubType(stripPackageObject(tp1.prefix), stripPackageObject(tp2.prefix)) ||
257258
thirdTryNamed(tp2)
258259
else
259260
( (tp1.name eq tp2.name)
@@ -352,7 +353,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
352353
tp1.info match {
353354
case info1: TypeAlias =>
354355
if (recur(info1.alias, tp2)) return true
355-
if (tp1.prefix.isStable) return false
356+
if (tp1.prefix.isStable) return tryPackagePrefix1(tp1, tp2)
356357
case _ =>
357358
if (tp1 eq NothingType) return true
358359
}
@@ -1057,6 +1058,33 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
10571058
}
10581059
}
10591060

1061+
/** If `tp` is a reference to a package object, a reference to the package itself,
1062+
* otherwise `tp`.
1063+
*/
1064+
private def stripPackageObject(tp: Type) = tp match {
1065+
case tp: TermRef if tp.symbol.isPackageObject => tp.symbol.owner.thisType
1066+
case tp: ThisType if tp.cls.isPackageObject => tp.cls.owner.thisType
1067+
case _ => tp
1068+
}
1069+
1070+
/** If prefix of `tp1` is a reference to a package object, retry with
1071+
* the prefix pointing to the package itself, otherwise `false`
1072+
*/
1073+
private def tryPackagePrefix1(tp1: NamedType, tp2: Type) = {
1074+
val pre1 = tp1.prefix
1075+
val pre1a = stripPackageObject(pre1)
1076+
(pre1a ne pre1) && isSubType(tp1.withPrefix(pre1a), tp2)
1077+
}
1078+
1079+
/** If prefix of `tp2` is a reference to a package object, retry with
1080+
* the prefix pointing to the package itself, otherwise `false`
1081+
*/
1082+
private def tryPackagePrefix2(tp1: Type, tp2: NamedType) = {
1083+
val pre2 = tp2.prefix
1084+
val pre2a = stripPackageObject(pre2)
1085+
(pre2a ne pre2) && isSubType(tp1, tp2.withPrefix(pre2a))
1086+
}
1087+
10601088
/** Optionally, the `n` such that `tp <:< ConstantType(Constant(n: Int))` */
10611089
def natValue(tp: Type): Option[Int] = constValue(tp) match {
10621090
case Some(Constant(n: Int)) if n >= 0 => Some(n)

0 commit comments

Comments
 (0)