Shortest answer: making Name
final suffices to persuade the compiler that zero
is not one. See this issue and environs.
It would warn on a type test, which is an isInstanceOf:
<console>:15: warning: fruitless type test: a value of type CaseMatching.Name cannot also be a CaseMatching.Id
case IdName(_, _: Id) =>
^
but not when testing equality, since equality is universal.
Here's another good one, case IdName(_, Id) =>
<console>:15: error: pattern type is incompatible with expected type;
found : CaseMatching.Id.type
required: CaseMatching.Name
Note: if you intended to match against the class, try `case _: Id`
case IdName(_, Id) =>
^
What you want is:
scala> IdName(Id(0), Name("A")) match { case IdName(_, id: Id.zero.type) => }
<console>:21: warning: fruitless type test: a value of type Name cannot also be a Id (the underlying of Id.zero.type)
IdName(Id(0), Name("A")) match { case IdName(_, id: Id.zero.type) => }
^
The singleton type contains only that value, so it uses eq
for the test; and as a type test, it also warns. (It uses eq
instead of equals
as of this week.)
Not sure how far this goes for you, but:
scala> :pa
// Entering paste mode (ctrl-D to finish)
sealed trait Id { def value: Long }
case class Nonzero(value: Long) extends Id
case object Zero extends Id { val value = 0L }
case class Name(value: String)
case class IdName(id: Id, name: Name)
// Exiting paste mode, now interpreting.
scala> IdName(Zero, Name("A")) match { case IdName(_, Zero) => 1 }
<console>:14: error: pattern type is incompatible with expected type;
found : Zero.type
required: Name
IdName(Zero, Name("A")) match { case IdName(_, Zero) => 1 }
^