E115: Unable to Emit Switch
This warning is emitted when the @switch annotation is used on a match expression that cannot be compiled to a JVM tableswitch or lookupswitch instruction.
If annotated with @switch, the compiler will verify that the match has been compiled to a tableswitch or lookupswitch and issue an error if it instead compiles into a series of conditional expressions.
The compiler will not apply the optimisation if:
- the matched value is not of type
Int,Byte,ShortorChar - the matched value is not a constant literal
- there are less than three cases
Example
import scala.annotation.switch
val ConstantB = 'B'
final val ConstantC = 'C'
def tokenMe(ch: Char) = (ch: @switch) match {
case '\t' | '\n' => 1
case 'A' => 2
case ConstantB => 3 // a non-literal may prevent switch generation: this would not compile
case ConstantC => 4 // a constant value is allowed
case _ => 5
}
Error
-- [E115] Syntax Warning: example.scala:5:38 -----------------------------------
5 |def tokenMe(ch: Char) = (ch: @switch) match {
| ^
| Could not emit switch for @switch annotated match
|
6 | case '\t' | '\n' => 1
7 |...
11 |}
|----------------------------------------------------------------------------
| Explanation (enabled by `-explain`)
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| If annotated with @switch, the compiler will verify that the match has been compiled to a
| tableswitch or lookupswitch and issue an error if it instead compiles into a series of conditional
| expressions. Example usage:
|
| val ConstantB = 'B'
| final val ConstantC = 'C'
| def tokenMe(ch: Char) = (ch: @switch) match {
| case '\t' | '\n' => 1
| case 'A' => 2
| case ConstantB => 3 // a non-literal may prevent switch generation: this would not compile
| case ConstantC => 4 // a constant value is allowed
| case _ => 5
| }
|
| The compiler will not apply the optimisation if:
| - the matched value is not of type Int, Byte, Short or Char
| - the matched value is not a constant literal
| - there are less than three cases
----------------------------------------------------------------------------
Solution
// Make all constants final so they can be inlined
import scala.annotation.switch
final val ConstantB = 'B'
final val ConstantC = 'C'
def tokenMe(ch: Char) = (ch: @switch) match {
case '\t' | '\n' => 1
case 'A' => 2
case ConstantB => 3
case ConstantC => 4
case _ => 5
}
// Or use literal values directly
import scala.annotation.switch
def tokenMe(ch: Char) = (ch: @switch) match {
case '\t' | '\n' => 1
case 'A' => 2
case 'B' => 3
case 'C' => 4
case _ => 5
}
// Or remove @switch if optimization is not required
val ConstantB = 'B'
final val ConstantC = 'C'
def tokenMe(ch: Char) = ch match {
case '\t' | '\n' => 1
case 'A' => 2
case ConstantB => 3
case ConstantC => 4
case _ => 5
}
In this article