Skip to content

Commit d90f307

Browse files
liufengyungsps
authored andcommitted
Fix scala#4314: revert changes in scala#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 0ccc736 commit d90f307

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

@@ -587,8 +588,8 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
587588
noClassConflict &&
588589
(!isSingleton(tp1) || tp1 <:< tp2) &&
589590
(!isSingleton(tp2) || tp2 <:< tp1) &&
590-
(!bases1.exists(_ is Final) || tp1 <:< tp2) &&
591-
(!bases2.exists(_ is Final) || tp2 <:< tp1)
591+
(!bases1.exists(_ is Final) || tp1 <:< maxTypeMap.apply(tp2)) &&
592+
(!bases2.exists(_ is Final) || tp2 <:< maxTypeMap.apply(tp1))
592593
}
593594
case OrType(tp1, tp2) =>
594595
recur(tp1) || recur(tp2)
@@ -607,6 +608,41 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
607608
res
608609
}
609610

611+
/** expose abstract type references to their bounds or tvars according to variance */
612+
private class AbstractTypeMap(maximize: Boolean)(implicit ctx: Context) extends TypeMap {
613+
def expose(lo: Type, hi: Type): Type =
614+
if (variance == 0)
615+
newTypeVar(TypeBounds(lo, hi))
616+
else if (variance == 1)
617+
if (maximize) hi else lo
618+
else
619+
if (maximize) lo else hi
620+
621+
def apply(tp: Type): Type = tp match {
622+
case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] =>
623+
val lo = this(tp.info.loBound)
624+
val hi = this(tp.info.hiBound)
625+
// See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala
626+
val exposed = expose(lo, hi)
627+
debug.println(s"$tp exposed to =====> $exposed")
628+
exposed
629+
630+
case AppliedType(tycon: TypeRef, args) if tycon.underlying.isInstanceOf[TypeBounds] =>
631+
val args2 = args.map(this)
632+
val lo = this(tycon.info.loBound).applyIfParameterized(args2)
633+
val hi = this(tycon.info.hiBound).applyIfParameterized(args2)
634+
val exposed = expose(lo, hi)
635+
debug.println(s"$tp exposed to =====> $exposed")
636+
exposed
637+
638+
case _ =>
639+
mapOver(tp)
640+
}
641+
}
642+
643+
private def minTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = false)
644+
private def maxTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = true)
645+
610646
/** Instantiate type `tp1` to be a subtype of `tp2`
611647
*
612648
* Return the instantiated type if type parameters and this type
@@ -616,25 +652,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
616652
*
617653
*/
618654
def instantiate(tp1: NamedType, tp2: Type)(implicit ctx: Context): Type = {
619-
// expose type param references to their bounds according to variance
620-
class AbstractTypeMap(maximize: Boolean)(implicit ctx: Context) extends ApproximatingTypeMap {
621-
variance = if (maximize) 1 else -1
622-
623-
def apply(tp: Type): Type = tp match {
624-
case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] =>
625-
val lo = this(tp.info.loBound)
626-
val hi = this(tp.info.hiBound)
627-
// See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala
628-
range(lo, hi)
629-
630-
case _ =>
631-
mapOver(tp)
632-
}
633-
}
634-
635-
def minTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = false)
636-
def maxTypeMap(implicit ctx: Context) = new AbstractTypeMap(maximize = true)
637-
638655
// Fix subtype checking for child instantiation,
639656
// such that `Foo(Test.this.foo) <:< Foo(Foo.this)`
640657
// 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)