Skip to content

Usage of @unchecked annotation with val is inconsistent between Scala 2 and 3 #10614

Closed
@SethTisue

Description

@SethTisue

in Scala 2, one annotates the scrutinee:

scala 2.13.4> val Some(x) = Option(3)
                                  ^
              warning: match may not be exhaustive.
              It would fail on the following input: None
val x: Int = 3

scala 2.13.4> val Some(x) = Option(3): @unchecked
val x: Int = 3

whereas in Scala 3.0.0-M2 under -source:3.1 one must annotate the pattern, while annotating the scrutinee is ignored:

scala> val Some(x) = Option(3)
1 |val Some(x) = Option(3)
  |    ^^^^^^^
  |pattern's type Some[Int] is more specialized than the right hand side expression's type Option[Int]
  |
  |If the narrowing is intentional, this can be communicated by writing `: @unchecked` after the full pattern.

scala> val Some(x) = Option(3): @unchecked                                                                              
1 |val Some(x) = Option(3): @unchecked
  |    ^^^^^^^
  |pattern's type Some[Int] is more specialized than the right hand side expression's type Option[Int] @unchecked
  |
  |If the narrowing is intentional, this can be communicated by writing `: @unchecked` after the full pattern.

scala> val Some(x): @unchecked = Option(3)
val x: Int = 3

Scala 3's behavior is as documented at https://dotty.epfl.ch/docs/reference/changed-features/pattern-bindings.html :

Sometimes one wants to decompose data anyway, even though the pattern is refutable. For instance, if at some point one knows that a list elems is non-empty one might want to decompose it like this:

val first :: rest = elems   // error

This works in Scala 2. In fact it is a typical use case for Scala 2's rules. But in Scala 3.1 it will give a type error. One can avoid the error by marking the pattern with an @unchecked annotation:

val first :: rest : @unchecked = elems   // OK

This will make the compiler accept the pattern binding. It might give an error at runtime instead, if the underlying assumption that elems can never be empty is wrong.

but I suggest that Scala 3 should adopt the Scala 2 convention, because:

  • it is more consistent with match; one also annotates the scrutinee with match, like (foo: @unchecked) match ...
  • we want to support cross-building between 2 and 3, and 2's style is the established precedent

(this came up at scala/bug#12245)

This became more important with the release of Scala 2.13.4, where improved exhaustivity checking has sent many users scurrying to add @unchecked to their matches.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions