Skip to content

Commit ab456d6

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 0528a7a commit ab456d6

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
@@ -232,13 +232,14 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
232232
def compareNamed(tp1: Type, tp2: NamedType): Boolean = {
233233
implicit val ctx: Context = this.ctx
234234
tp2.info match {
235-
case info2: TypeAlias => recur(tp1, info2.alias)
235+
case info2: TypeAlias =>
236+
recur(tp1, info2.alias) || tryPackagePrefix2(tp1, tp2)
236237
case _ => tp1 match {
237238
case tp1: NamedType =>
238239
tp1.info match {
239240
case info1: TypeAlias =>
240241
if (recur(info1.alias, tp2)) return true
241-
if (tp1.prefix.isStable) return false
242+
if (tp1.prefix.isStable) return tryPackagePrefix1(tp1, tp2)
242243
// If tp1.prefix is stable, the alias does contain all information about the original ref, so
243244
// there's no need to try something else. (This is important for performance).
244245
// To see why we cannot in general stop here, consider:
@@ -260,7 +261,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
260261
if ((sym1 ne NoSymbol) && (sym1 eq sym2))
261262
ctx.erasedTypes ||
262263
sym1.isStaticOwner ||
263-
isSubType(tp1.prefix, tp2.prefix) ||
264+
isSubType(stripPackageObject(tp1.prefix), stripPackageObject(tp2.prefix)) ||
264265
thirdTryNamed(tp2)
265266
else
266267
( (tp1.name eq tp2.name)
@@ -359,7 +360,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
359360
tp1.info match {
360361
case info1: TypeAlias =>
361362
if (recur(info1.alias, tp2)) return true
362-
if (tp1.prefix.isStable) return false
363+
if (tp1.prefix.isStable) return tryPackagePrefix1(tp1, tp2)
363364
case _ =>
364365
if (tp1 eq NothingType) return true
365366
}
@@ -1074,6 +1075,33 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
10741075
}
10751076
}
10761077

1078+
/** If `tp` is a reference to a package object, a reference to the package itself,
1079+
* otherwise `tp`.
1080+
*/
1081+
private def stripPackageObject(tp: Type) = tp match {
1082+
case tp: TermRef if tp.symbol.isPackageObject => tp.symbol.owner.thisType
1083+
case tp: ThisType if tp.cls.isPackageObject => tp.cls.owner.thisType
1084+
case _ => tp
1085+
}
1086+
1087+
/** If prefix of `tp1` is a reference to a package object, retry with
1088+
* the prefix pointing to the package itself, otherwise `false`
1089+
*/
1090+
private def tryPackagePrefix1(tp1: NamedType, tp2: Type) = {
1091+
val pre1 = tp1.prefix
1092+
val pre1a = stripPackageObject(pre1)
1093+
(pre1a ne pre1) && isSubType(tp1.withPrefix(pre1a), tp2)
1094+
}
1095+
1096+
/** If prefix of `tp2` is a reference to a package object, retry with
1097+
* the prefix pointing to the package itself, otherwise `false`
1098+
*/
1099+
private def tryPackagePrefix2(tp1: Type, tp2: NamedType) = {
1100+
val pre2 = tp2.prefix
1101+
val pre2a = stripPackageObject(pre2)
1102+
(pre2a ne pre2) && isSubType(tp1, tp2.withPrefix(pre2a))
1103+
}
1104+
10771105
/** Optionally, the `n` such that `tp <:< ConstantType(Constant(n: Int))` */
10781106
def natValue(tp: Type): Option[Int] = constValue(tp) match {
10791107
case Some(Constant(n: Int)) if n >= 0 => Some(n)

0 commit comments

Comments
 (0)