bug
bug copied to clipboard
generate a switch whenever possible
(I'm consolidating related tickets: see also #1452, #1456, #1457, #1458, #6955, #6956)
Terms:
- "intlike type" is any of Int, Short, Byte, or Char.
- "intlike" means an intlike literal or intlike identifier.
- "intlike literal" means any literal constant with an intlike type.
- "intlike identifier" means an identifier which can be statically determined to have the following properties:
- immutable (i.e. a val)
- not overridable (i.e. final or enclosed in a final container)
- assigned a value which can be statically reduced to an intlike literal. This means arithmetic operations only, on intlikes.
scala should generate tableswitch/lookupswitch bytecode whenever the following conditions hold:
- a) the scrutinee is any expression with an intlike result type.
- a1) or, if b) and c) hold, then if the scrutinee is AnyVal or Any, a switch can still be generated by inserting if/then/else logic before the switch.
- b) all non-default cases are intlike.
- c) if there is a default case, it either has no type annotation, or a type annotation which matches all intlike values.
At present, an identifier in a match statement will suppress the creation of a switch statement 100% of the time if it makes it to the pattern matcher stage. When scala's constant folder replaces the identifier with the constant before reaching that point, the switch can be created; but this takes place only in a fraction of the cases where it's desirable.
Imported From: https://issues.scala-lang.org/browse/SI-2398?orig=1 Reporter: @paulp See #1452, #1456, #1457, #1458, #6955, #6956
@adriaanm said: also applies when scrutinee is value class that unboxes to switchable type
this ticket seems not to have been looked at in a long time. anyone know what the current state is, in Scala 2 and/or 3? not sure whether to add the "help wanted" label and/or the "fixed in Scala 3" labels
As of 2.13.16
class C {
final val K: Int = 5
def f(x: Int) =
x match {
case 1 => ""
case 2 => ""
case 3 => ""
case 4 => ""
case K => ""
case 6 => ""
case 7 => ""
case 8 => ""
case 9 => ""
case 10 => ""
}
}
produces only if/else.
3.6.4 generates a split tableswitch
3: tableswitch { // 1 to 4
1: 32
2: 35
3: 38
4: 41
default: 44
}
32: ldc #21 // String
34: areturn
35: ldc #21 // String
37: areturn
38: ldc #21 // String
40: areturn
41: ldc #21 // String
43: areturn
44: aload_0
45: invokevirtual #23 // Method K:()I
48: iload_2
49: if_icmpne 55
52: ldc #21 // String
54: areturn
55: iload_2
56: tableswitch { // 6 to 10
6: 92
7: 95
8: 98
9: 101
10: 104
default: 107
}
92: ldc #21 // String
94: areturn
Using inline val K of course makes it a constant type again. My understanding is that the tricky final val syntax will be removed eventually.
It would be nice if it warned for this case.
I am here because of https://github.com/scala/scala/blob/v2.13.16/src/reflect/scala/reflect/internal/Chars.scala#L27
I was there because Dotty has stale comments dating back to ancient times, as when archeologists announce they've found a 3000-yr-old clay pot with wine or porridge, or "Incredible Prohibition-era whiskey bottles emerge from sand at Jersey Shore beach"