From 3fa823b75636e149391497e4d869efbb23408560 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 2 Feb 2021 14:09:26 +0000 Subject: [PATCH] Enumerate subtypes by approximating type skolems to their upper bound --- .../nsc/transform/patmat/MatchAnalysis.scala | 13 +++++++++--- test/files/pos/t9657.scala | 21 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 test/files/pos/t9657.scala diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index 2be8a7b6bc67..281058cdcad0 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -95,9 +95,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 } diff --git a/test/files/pos/t9657.scala b/test/files/pos/t9657.scala new file mode 100644 index 000000000000..eb51a41b0f37 --- /dev/null +++ b/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))) + } +}