Skip to content

Commit c7c4ffc

Browse files
committed
Restrict dubious subtype rule and document it better
We previously implemented a rule that A.this <: B.this if A and B are mutually superclasses of the other's self type. We now apply that rule only if A.this and B.this occur as prefixes in a comparison like A.this.T <:< B.this.T And we document why that choice was made.
1 parent 2d7ee66 commit c7c4ffc

File tree

1 file changed

+41
-9
lines changed

1 file changed

+41
-9
lines changed

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

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,13 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
261261
if ((sym1 ne NoSymbol) && (sym1 eq sym2))
262262
ctx.erasedTypes ||
263263
sym1.isStaticOwner ||
264-
isSubType(tp1.prefix, tp2.prefix) ||
264+
isSubPrefix(tp1.prefix, tp2.prefix) ||
265265
thirdTryNamed(tp2)
266266
else
267267
( (tp1.name eq tp2.name)
268268
&& tp1.isMemberRef
269269
&& tp2.isMemberRef
270-
&& isSubType(tp1.prefix, tp2.prefix)
270+
&& isSubPrefix(tp1.prefix, tp2.prefix)
271271
&& tp1.signature == tp2.signature
272272
&& !(sym1.isClass && sym2.isClass) // class types don't subtype each other
273273
) ||
@@ -296,12 +296,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
296296
def compareThis = {
297297
val cls2 = tp2.cls
298298
tp1 match {
299-
case tp1: ThisType =>
300-
// We treat two prefixes A.this, B.this as equivalent if
301-
// A's selftype derives from B and B's selftype derives from A.
302-
val cls1 = tp1.cls
303-
cls1.classInfo.selfType.derivesFrom(cls2) &&
304-
cls2.classInfo.selfType.derivesFrom(cls1)
305299
case tp1: NamedType if cls2.is(Module) && cls2.eq(tp1.widen.typeSymbol) =>
306300
cls2.isStaticOwner ||
307301
recur(tp1.prefix, cls2.owner.thisType) ||
@@ -819,6 +813,44 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
819813
false
820814
}
821815

816+
/** When called from `pre1.A <:< pre2.A` does `pre1` relate to `pre2` so that
817+
* the subtype test is true? This is the case if `pre1 <:< pre2`, or
818+
* `pre1` and `pre2` are both this-types of related classes. Here, two classes
819+
* are related if each of them has a self type that derives from the other.
820+
*
821+
* This criterion is a bit dubious. I.e. in the test
822+
*
823+
* A.this.T <:< B.this.T
824+
*
825+
* where `T` is the same type, what relationship must exist between A and B
826+
* for the test to be guaranteed true? The problem is we can't tell without additional
827+
* info. One could be an outer this at the point where we do the test, but that
828+
* location is unknown to us.
829+
*
830+
* The conservative choice would be to require A == B, but then some tests involving
831+
* self types fail. Specifically, t360, t361 and pat_iuli fail the pickling test, and
832+
* Namer fails to compile. At line 203, we get
833+
*
834+
* val Deriver : Property.Key[typer.Deriver] = new Property.Key
835+
* ^
836+
* value Deriver in class Namer is not a legal implementation of `Deriver` in class Namer.
837+
* its type dotty.tools.dotc.util.Property.Key[Namer.this.Deriver]
838+
|* does not conform to dotty.tools.dotc.util.Property.Key[Typer.this.Deriver & Namer.this.Deriver]
839+
*/
840+
def isSubPrefix(pre1: Type, pre2: Type): Boolean =
841+
pre1 match
842+
case pre1: ThisType =>
843+
pre2 match
844+
case pre2: ThisType =>
845+
if pre1.cls.classInfo.selfType.derivesFrom(pre2.cls)
846+
&& pre2.cls.classInfo.selfType.derivesFrom(pre1.cls)
847+
then
848+
subtyping.println(i"assume equal prefixes $pre1 $pre2")
849+
return true
850+
case _ =>
851+
case _ =>
852+
isSubType(pre1, pre2)
853+
822854
/** Subtype test for the hk application `tp2 = tycon2[args2]`.
823855
*/
824856
def compareAppliedType2(tp2: AppliedType, tycon2: Type, args2: List[Type]): Boolean = {
@@ -857,7 +889,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
857889

858890
val res = (
859891
tycon1sym == tycon2sym
860-
&& isSubType(tycon1.prefix, tycon2.prefix)
892+
&& isSubPrefix(tycon1.prefix, tycon2.prefix)
861893
|| byGadtBounds(tycon1sym, tycon2, fromAbove = true)
862894
|| byGadtBounds(tycon2sym, tycon1, fromAbove = false)
863895
) && {

0 commit comments

Comments
 (0)