E115: Unable to Emit Switch
E115: Unable to Emit Switch (스위치 생성 불가)
@switch 어노테이션을 붙인 match 표현식을 JVM의 tableswitch나 lookupswitch 명령어로 컴파일할 수 없을 때 나오는 경고예요.
본문
@switch로 어노테이션하면 컴파일러는 그 match가 tableswitch 또는 lookupswitch로 컴파일됐는지 확인하고, 만약 일련의 조건식으로 컴파일된다면 에러를 띄워요.
컴파일러는 다음의 경우 최적화를 적용하지 않아요.
- 매치 대상 값이
Int,Byte,Short,Char타입이 아닐 때 - 매치 대상 값이 상수 리터럴이 아닐 때
- case가 세 개 미만일 때
예시
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
}
에러 메시지
-- [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
----------------------------------------------------------------------------
해결 방법
모든 상수를 final로 만들어 인라인되게 하거나, 리터럴 값을 직접 쓰거나, 최적화가 필요 없다면 @switch를 제거하면 돼요.
// 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
}