Skip to content

Commit f03eade

Browse files
committed
handle abstract types in child's parent list
1 parent 20552e1 commit f03eade

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
@@ -602,10 +602,19 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
602602
// map `ThisType` of `tp1` to a type variable
603603
// precondition: `tp1` should have the shape `path.Child`, thus `ThisType` is always covariant
604604
val thisTypeMap = new TypeMap {
605-
def apply(t: Type): Type = t match {
605+
def apply(t: Type): Type = t.dealias match {
606606
case tp @ ThisType(tref) if !tref.symbol.isStaticOwner =>
607607
if (tref.symbol.is(Module)) mapOver(tref)
608608
else newTypeVar(TypeBounds.upper(tp.underlying))
609+
case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] =>
610+
// See tests/patmat/3645b.scala
611+
val exposed =
612+
if (variance == 0) newTypeVar(tp.underlying.bounds)
613+
else if (variance == 1) mapOver(tp.underlying.hiBound)
614+
else mapOver(tp.underlying.loBound)
615+
616+
debug.println(s"$tp exposed to =====> $exposed")
617+
exposed
609618
case _ =>
610619
mapOver(t)
611620
}
@@ -644,13 +653,19 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
644653
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
645654
val protoTp1 = thisTypeMap(tp1.appliedTo(tvars))
646655

656+
// tests/patmat/3645b.scala
657+
def parentQualify = tp1.widen.classSymbol.info.parents.exists { parent =>
658+
(parent.argInfos.nonEmpty || parent.abstractTypeMembers.nonEmpty) &&
659+
instantiate(parent, tp2)(ctx.fresh.setNewTyperState()).exists
660+
}
661+
647662
if (protoTp1 <:< tp2) {
648663
if (isFullyDefined(protoTp1, force)) protoTp1
649664
else instUndetMap(protoTp1)
650665
}
651666
else {
652667
val protoTp2 = typeParamMap(tp2)
653-
if (protoTp1 <:< protoTp2) {
668+
if (protoTp1 <:< protoTp2 || parentQualify) {
654669
if (isFullyDefined(AndType(protoTp1, protoTp2), force)) protoTp1
655670
else instUndetMap(protoTp1)
656671
}

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)