Skip to content

Commit 06941b2

Browse files
authored
Merge pull request #8944 from dotty-staging/fix-#8933
Fix #8933: Fix eta expansion when comparing hk types
2 parents 5aec4f8 + c7c4ffc commit 06941b2

File tree

2 files changed

+57
-10
lines changed

2 files changed

+57
-10
lines changed

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

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,13 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
262262
if ((sym1 ne NoSymbol) && (sym1 eq sym2))
263263
ctx.erasedTypes ||
264264
sym1.isStaticOwner ||
265-
isSubType(tp1.prefix, tp2.prefix) ||
265+
isSubPrefix(tp1.prefix, tp2.prefix) ||
266266
thirdTryNamed(tp2)
267267
else
268268
( (tp1.name eq tp2.name)
269269
&& tp1.isMemberRef
270270
&& tp2.isMemberRef
271-
&& isSubType(tp1.prefix, tp2.prefix)
271+
&& isSubPrefix(tp1.prefix, tp2.prefix)
272272
&& tp1.signature == tp2.signature
273273
&& !(sym1.isClass && sym2.isClass) // class types don't subtype each other
274274
) ||
@@ -297,12 +297,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
297297
def compareThis = {
298298
val cls2 = tp2.cls
299299
tp1 match {
300-
case tp1: ThisType =>
301-
// We treat two prefixes A.this, B.this as equivalent if
302-
// A's selftype derives from B and B's selftype derives from A.
303-
val cls1 = tp1.cls
304-
cls1.classInfo.selfType.derivesFrom(cls2) &&
305-
cls2.classInfo.selfType.derivesFrom(cls1)
306300
case tp1: NamedType if cls2.is(Module) && cls2.eq(tp1.widen.typeSymbol) =>
307301
cls2.isStaticOwner ||
308302
recur(tp1.prefix, cls2.owner.thisType) ||
@@ -498,7 +492,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
498492
if (base.typeSymbol == cls2) return true
499493
}
500494
else if tp1.isLambdaSub && !tp1.isAnyKind then
501-
return recur(tp1, EtaExpansion(cls2.typeRef))
495+
return recur(tp1, EtaExpansion(tp2))
502496
fourthTry
503497
}
504498

@@ -820,6 +814,44 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
820814
false
821815
}
822816

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

859891
val res = (
860892
tycon1sym == tycon2sym
861-
&& isSubType(tycon1.prefix, tycon2.prefix)
893+
&& isSubPrefix(tycon1.prefix, tycon2.prefix)
862894
|| byGadtBounds(tycon1sym, tycon2, fromAbove = true)
863895
|| byGadtBounds(tycon2sym, tycon1, fromAbove = false)
864896
) && {

tests/pos/i8933.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait Foo[F[_]]
2+
3+
trait Top {
4+
type F[X]
5+
def foo: Foo[F]
6+
}
7+
8+
trait Left extends Top
9+
10+
trait Right extends Top {
11+
trait F[X]
12+
def foo: Foo[F] = new Foo[F] {}
13+
}
14+
15+
class Bottom extends Left with Right

0 commit comments

Comments
 (0)