Skip to content

Commit 727b29d

Browse files
committed
handle abstract types in child's parent list
1 parent 27ccf15 commit 727b29d

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,10 +583,19 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
583583
// map `ThisType` of `tp1` to a type variable
584584
// precondition: `tp1` should have the shape `path.Child`, thus `ThisType` is always covariant
585585
val thisTypeMap = new TypeMap {
586-
def apply(t: Type): Type = t match {
586+
def apply(t: Type): Type = t.dealias match {
587587
case tp @ ThisType(tref) if !tref.symbol.isStaticOwner =>
588588
if (tref.symbol.is(Module)) mapOver(tref)
589589
else newTypeVar(TypeBounds.upper(tp.underlying))
590+
case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] =>
591+
// See tests/patmat/3645b.scala
592+
val exposed =
593+
if (variance == 0) newTypeVar(tp.underlying.bounds)
594+
else if (variance == 1) mapOver(tp.underlying.hiBound)
595+
else mapOver(tp.underlying.loBound)
596+
597+
debug.println(s"$tp exposed to =====> $exposed")
598+
exposed
590599
case _ =>
591600
mapOver(t)
592601
}
@@ -625,13 +634,19 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
625634
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
626635
val protoTp1 = thisTypeMap(tp1.appliedTo(tvars))
627636

637+
// tests/patmat/3645b.scala
638+
def parentQualify = tp1.widen.classSymbol.info.parents.exists { parent =>
639+
(parent.argInfos.nonEmpty || parent.abstractTypeMembers.nonEmpty) &&
640+
instantiate(parent, tp2)(ctx.fresh.setNewTyperState()).exists
641+
}
642+
628643
if (protoTp1 <:< tp2) {
629644
if (isFullyDefined(protoTp1, force)) protoTp1
630645
else instUndetMap(protoTp1)
631646
}
632647
else {
633648
val protoTp2 = typeParamMap(tp2)
634-
if (protoTp1 <:< protoTp2) {
649+
if (protoTp1 <:< protoTp2 || parentQualify) {
635650
if (isFullyDefined(AndType(protoTp1, protoTp2), force)) protoTp1
636651
else instUndetMap(protoTp1)
637652
}

tests/patmat/3645b.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
21: Pattern Match Exhaustivity: K3, K2

tests/patmat/3645b.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
object App {
2+
def main(args: Array[String]): Unit = {
3+
trait FooT {
4+
type T
5+
def subst[F[_]](fa: F[T]): F[Int]
6+
}
7+
val Foo: FooT = new FooT {
8+
type T = Int
9+
10+
def subst[F[_]](fa: F[T]): F[Int] = fa
11+
}
12+
type Foo = Foo.T
13+
type Bar = Foo
14+
15+
sealed abstract class K[A]
16+
final case object K1 extends K[Int]
17+
final case object K2 extends K[Foo]
18+
final case object K3 extends K[Bar]
19+
20+
val foo: K[Int] = Foo.subst[K](K2)
21+
def get(k: K[Int]): Unit = k match {
22+
case K1 => ()
23+
// case K2 => ()
24+
// case K3 => ()
25+
}
26+
27+
get(foo)
28+
}
29+
}

0 commit comments

Comments
 (0)