Skip to content

Commit 84cf261

Browse files
committed
Fix #4314: revert changes in #4299
1. ApproximatingTypeMap produces Nothing, which is not what is needed. 2. Avoid blind erasure which lose information about the pattern, see tests/patmat/i4314b.scala
1 parent ac84047 commit 84cf261

File tree

4 files changed

+73
-34
lines changed

4 files changed

+73
-34
lines changed

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

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ trait SpaceLogic {
113113
case Prod(tp, fun, sym, spaces, full) =>
114114
val sp = Prod(tp, fun, sym, spaces.map(simplify(_)), full)
115115
if (sp.params.contains(Empty)) Empty
116+
else if (canDecompose(tp) && decompose(tp).isEmpty) Empty
116117
else sp
117118
case Or(spaces) =>
118119
val set = spaces.map(simplify(_)).flatMap {
@@ -349,18 +350,18 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
349350
Empty
350351
}
351352

352-
/* Erase a type binding according to erasure semantics in pattern matching */
353-
def erase(tp: Type): Type = tp match {
354-
case tp @ AppliedType(tycon, args) =>
355-
if (tycon.isRef(defn.ArrayClass)) tp.derivedAppliedType(tycon, args.map(erase))
356-
else tp.derivedAppliedType(tycon, args.map(t => WildcardType))
357-
case OrType(tp1, tp2) =>
358-
OrType(erase(tp1), erase(tp2))
359-
case AndType(tp1, tp2) =>
360-
AndType(erase(tp1), erase(tp2))
361-
case tp @ RefinedType(parent, refinedName, _) if refinedName.isTermName => // see pos/dependent-extractors.scala
362-
tp.derivedRefinedType(erase(parent), refinedName, WildcardType)
363-
case _ => tp
353+
/* Erase pattern bound types with WildcardType */
354+
def erase(tp: Type) = {
355+
def isPatternTypeSymbol(sym: Symbol) = !sym.isClass && sym.is(Case)
356+
357+
val map = new TypeMap {
358+
def apply(tp: Type) = tp match {
359+
case tref: TypeRef if isPatternTypeSymbol(tref.typeSymbol) => WildcardType(tref.underlying.bounds)
360+
case _ => mapOver(tp)
361+
}
362+
}
363+
364+
map(tp)
364365
}
365366

366367
/** Space of the pattern: unapplySeq(a, b, c: _*)
@@ -384,7 +385,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
384385
/** Is `tp1` a subtype of `tp2`? */
385386
def isSubType(tp1: Type, tp2: Type): Boolean = {
386387
val res = (tp1 != nullType || tp2 == nullType) && tp1 <:< tp2
387-
debug.println(s"${tp1.show} <:< ${tp2.show} = $res")
388+
debug.println(s"${tp1} <:< ${tp2} = $res")
388389
res
389390
}
390391

@@ -576,8 +577,8 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
576577
noClassConflict &&
577578
(!isSingleton(tp1) || tp1 <:< tp2) &&
578579
(!isSingleton(tp2) || tp2 <:< tp1) &&
579-
(!bases1.exists(_ is Final) || tp1 <:< tp2) &&
580-
(!bases2.exists(_ is Final) || tp2 <:< tp1)
580+
(!bases1.exists(_ is Final) || tp1 <:< maxTypeMap.apply(tp2)) &&
581+
(!bases2.exists(_ is Final) || tp2 <:< maxTypeMap.apply(tp1))
581582
}
582583
case OrType(tp1, tp2) =>
583584
recur(tp1) || recur(tp2)
@@ -596,6 +597,41 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
596597
res
597598
}
598599

600+
/** expose abstract type references to their bounds or tvars according to variance */
601+
private class AbstractTypeMap(maximize: Boolean)(implicit ctx: Context) extends TypeMap {
602+
def expose(lo: Type, hi: Type): Type =
603+
if (variance == 0)
604+
newTypeVar(TypeBounds(lo, hi))
605+
else if (variance == 1)
606+
if (maximize) hi else lo
607+
else
608+
if (maximize) lo else hi
609+
610+
def apply(tp: Type): Type = tp match {
611+
case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] =>
612+
val lo = this(tp.info.loBound)
613+
val hi = this(tp.info.hiBound)
614+
// See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala
615+
val exposed = expose(lo, hi)
616+
debug.println(s"$tp exposed to =====> $exposed")
617+
exposed
618+
619+
case AppliedType(tycon: TypeRef, args) if tycon.underlying.isInstanceOf[TypeBounds] =>
620+
val args2 = args.map(this)
621+
val lo = this(tycon.info.loBound).applyIfParameterized(args2)
622+
val hi = this(tycon.info.hiBound).applyIfParameterized(args2)
623+
val exposed = expose(lo, hi)
624+
debug.println(s"$tp exposed to =====> $exposed")
625+
exposed
626+
627+
case _ =>
628+
mapOver(tp)
629+
}
630+
}
631+
632+
private def minTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = false)
633+
private def maxTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = true)
634+
599635
/** Instantiate type `tp1` to be a subtype of `tp2`
600636
*
601637
* Return the instantiated type if type parameters and this type
@@ -605,25 +641,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
605641
*
606642
*/
607643
def instantiate(tp1: NamedType, tp2: Type)(implicit ctx: Context): Type = {
608-
// expose type param references to their bounds according to variance
609-
class AbstractTypeMap(maximize: Boolean)(implicit ctx: Context) extends ApproximatingTypeMap {
610-
variance = if (maximize) 1 else -1
611-
612-
def apply(tp: Type): Type = tp match {
613-
case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] =>
614-
val lo = this(tp.info.loBound)
615-
val hi = this(tp.info.hiBound)
616-
// See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala
617-
range(lo, hi)
618-
619-
case _ =>
620-
mapOver(tp)
621-
}
622-
}
623-
624-
def minTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = false)
625-
def maxTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = true)
626-
627644
// Fix subtype checking for child instantiation,
628645
// such that `Foo(Test.this.foo) <:< Foo(Foo.this)`
629646
// See tests/patmat/i3938.scala

tests/patmat/i4314.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
sealed trait Foo[A]
2+
case class One[A]() extends Foo[A]
3+
sealed abstract case class Bar[A]() extends Foo[A]
4+
class Two() extends Bar[String]
5+
6+
object Test {
7+
def test(x: Foo[Int]) = x match {
8+
case One() =>
9+
}
10+
}

tests/patmat/i4314b.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
9: Match case Unreachable

tests/patmat/i4314b.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
sealed trait Foo[A]
2+
case class One[A]() extends Foo[A]
3+
sealed abstract case class Bar[A]() extends Foo[A]
4+
class Two() extends Bar[String]
5+
6+
object Test {
7+
def test(x: Foo[Int]) = x match {
8+
case One() =>
9+
case Bar() =>
10+
}
11+
}

0 commit comments

Comments
 (0)