Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect 'warning: unreachable code' on Type Member #9657

Closed
scabug opened this issue Feb 16, 2016 · 2 comments · Fixed by scala/scala#9479
Closed

Incorrect 'warning: unreachable code' on Type Member #9657

scabug opened this issue Feb 16, 2016 · 2 comments · Fixed by scala/scala#9479
Assignees
Labels
Milestone

Comments

@scabug
Copy link

scabug commented Feb 16, 2016

Given:

scala> sealed trait PowerSource 
defined trait PowerSource

scala> case object Petrol extends PowerSource
defined object Petrol

scala> case object Pedal extends PowerSource
defined object Pedal

scala> sealed abstract class Vehicle {
     |   type A <: PowerSource
     | }
defined class Vehicle

scala> case object Bicycle extends Vehicle {
     |   type A = Pedal.type
     | }

scala> case class Bus(fuel: Int) extends Vehicle {
     |   type A = Petrol.type
     | }
defined class Bus

scala> case class Car(fuel: Int) extends Vehicle {
     |   type A = Petrol.type
     | }

And now the refuel function. Observe that there's an unreachable code warning that's not true.

scala> def refuel[P <: Petrol.type](vehicle: Vehicle {type A = P} ): Vehicle = vehicle match {
     |   case Car(_) => Car(100)
     |   case Bus(_) => Bus(100)
     | }
<console>:20: warning: unreachable code
         case Bus(_) => Bus(100)
                           ^
refuel: [P <: Petrol.type](vehicle: Vehicle{type A = P})Vehicle

scala> refuel(Car(100))
res6: Vehicle = Car(100)

scala> refuel(Bus(5))
res7: Vehicle = Bus(100)
@scabug
Copy link
Author

scabug commented Feb 16, 2016

Imported From: https://issues.scala-lang.org/browse/SI-9657?orig=1
Reporter: Kevin Meredith (kevinmeredith)
Affected Versions: 2.12.0-M3

@scabug
Copy link
Author

scabug commented Feb 16, 2016

@retronym said (edited on Feb 16, 2016 1:46:00 PM UTC):
This logic is incorrect in the pattern matcher:

        case sym: RefinementClassSymbol =>
          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))
          }
          else Nil

It is saying: if the scrutinee type is a refined type, then the domain includes the types of the sealed children of its parents, given that they conform to the scrutinee type. However, none of Bicycle.type, Bus, or Car conform to the refinement of Vehicle, so they are discarded.

Instead, we should only filter out sealed children for which we statically know there could not be a value of a third type the conforms both to the scrutinee type and to the sealed class. We have some machinery for this in CheckabilityChecker and matchesPattern, but I don't think it would be straightforward to plug this all together and to make it smart enough to deal with type members.

As a workaround, I would suggest avoiding pattern matching on refinement types, and instead go for:

class Test {
  def refuel[P <: Petrol.type](vehicle: Vehicle {type A = P} ): Vehicle = (vehicle: Vehicle) match {
    case Car(_) => Car(100)
    case Bus(_) => Bus(100)
    case Bicycle => throw new IllegalStateException("cannot get here")
  }
}

Incidentally, I have recently fixed a bug (fix due in Scala 2.12.0-M4) that results in incorrect pattern matcher analysis in some cases when sibling child case classes use the same name for parameters. I would recommend using distinct names in the meantime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants