Skip to content

Commit

Permalink
Enumerate subtypes by approximating type skolems to their upper bound
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Feb 2, 2021
1 parent 0ab9086 commit 93ed083
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
13 changes: 10 additions & 3 deletions src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
Expand Up @@ -96,9 +96,16 @@ trait TreeAndTypeAnalysis extends Debugging {
val parentSubtypes = tp.parents.flatMap(parent => enumerateSubtypes(parent, grouped))
if (parentSubtypes exists (_.nonEmpty)) {
// If any of the parents is enumerable, then the refinement type is enumerable.
// We must only include subtypes of the parents that conform to `tp`.
// See neg/virtpatmat_exhaust_compound.scala for an example.
parentSubtypes map (_.filter(_ <:< tp))
// We must only include subtypes of the parents that conform to `tpApprox`.
// See neg/virtpatmat_exhaust_compound.scala and pos/t9657.scala for examples.
val approximateTypeSkolemsToUpperBound = new TypeMap { // from approximateAbstracts
def apply(tp: Type): Type = tp.dealiasWiden match {
case TypeRef(_, sym, _) if sym.isTypeSkolem => tp.upperBound
case _ => mapOver(tp)
}
}
val tpApprox = approximateTypeSkolemsToUpperBound(tp)
parentSubtypes.map(_.filter(_ <:< tpApprox))
}
else Nil
// make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte
Expand Down
21 changes: 21 additions & 0 deletions test/files/pos/t9657.scala
@@ -0,0 +1,21 @@
// scalac: -Werror
sealed trait PowerSource
case object Petrol extends PowerSource
case object Pedal extends PowerSource

sealed abstract class Vehicle { type A <: PowerSource }
case object Bicycle extends Vehicle { type A = Pedal.type }
case class Bus(fuel: Int) extends Vehicle { type A = Petrol.type }
case class Car(fuel: Int) extends Vehicle { type A = Petrol.type }

object Test {
def refuel[P <: Petrol.type](vehicle: Vehicle { type A = P }): Vehicle = vehicle match {
case Car(_) => Car(100)
case Bus(_) => Bus(100) // was: "unreachable code" warning
}

def main(args: Array[String]): Unit = {
println(refuel(Car(100)))
println(refuel(Bus(5)))
}
}

0 comments on commit 93ed083

Please sign in to comment.