How to use @unchecked when matching a type parameter bounds

I’ve encountered a problem with exhaustivity checking and tried to use the @unchecked annotation and ran into another compiling issue, so wanted to check if there is another way to use the annotation or I’m doing something wrong

package com.scala.example

sealed trait Fruit
class Apple extends Fruit
class Banana extends Fruit

abstract class Stack[T <: Fruit]

class AppleStack extends Stack[Apple]
class BananaStack extends Stack[Banana]

object Main {
  def main(args: Array[String]): Unit = {
    val appleStack = new AppleStack
    whichStack(appleStack)
  }

  def whichStack(stack: Stack[_]): Unit = {
    stack match {
      case _: AppleStack => println("This is apple stack")
      case _: BananaStack => println("This is banana stack")
    }
  }
}

Compiling this with latest scala 2.13.5 with sbt-tpolecat flags I encounter

match may not be exhaustive.
[error] It would fail on the following input: (x: com.scala.example.Stack[?] forSome x not in (com.scala.example.AppleStack, com.scala.example.BananaStack))
[error]     stack match {
[error]     ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed

Following the suggestion of annotating with @unchecked making the line (stack: @unchecked) match { runs into another compilation failure

 type arguments [_$1] do not conform to class Stack's type parameter bounds [T <: com.scala.example.Fruit]
[error]     (stack: @unchecked) match {
[error]              ^
[info] Nothing <: _$1?
[info] true
[info] _$1 <: com.scala.example.Fruit?
[info] false
[error] one error found
[error] (Compile / compileIncremental) Compilation failed

Hey,

I am not sure if this is the right place for this question (or if https://users.scala-lang.org/ would have been more fitting). I hope one is still allowed to reply :sweat_smile:

Anyway:
The first option to solve the original issue would be to make class Stack sealed.

Otherwise, the exhaustivity warning is not strictly wrong in the first place. I believe the exhaustivity checking for pattern matches on unsealed classes has been changed with Scala 2.13.4 (see Release Scala 2.13.4 · scala/scala · GitHub - the paragraph on Pattern matching).

The second option to get your code with the @unchecked to compile was by repeating the type bound for Stack in the method definition, like this

  def whichStack(stack: Stack[_ <: Fruit]): Unit = {
    (stack: @unchecked) match {
      case _: AppleStack => println("This is apple stack")
      case _: BananaStack => println("This is banana stack")
    }
  }

Unfortunately, I cannot explain why this is required under these circumstances.

2 Likes

I am not sure if this is the right place for this question (or if https://users.scala-lang.org/ would have been more fitting).

Oops, I knew I was doing something wrong when I couldn’t find my past posts :man_facepalming: Sorry for posting this here. Your suggestion works, thanks a lot!

1 Like