Skip to content

Emit switch bytecode when matching unions of a switchable type #20410

Closed
@dwickern

Description

@dwickern

Scala emits a switch instruction when matching on Int or String but not when matching on a union of those types.

Compiler version

3.3.3, 3.4.1

Minimized code

def matchInt(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case 4 => "four"
  case 5 => "five"
}

def matchIntUnion(x: 1 | 2 | 3 | 4 | 5): String = x match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case 4 => "four"
  case 5 => "five"
}

def matchString(s: String): Int = s match {
  case "one"   => 1
  case "two"   => 2
  case "three" => 3
  case "four"  => 4
  case "five"  => 5
}

def matchStringUnion(s: "one" | "two" | "three" | "four" | "five"): Int = s match {
  case "one"   => 1
  case "two"   => 2
  case "three" => 3
  case "four"  => 4
  case "five"  => 5
}

Output

The above code (de)compiles to:

public String matchInt(final int x) {
    switch (x) {
        case 1:
            return "one";
        case 2:
            return "two";
        case 3:
            return "three";
        case 4:
            return "four";
        case 5:
            return "five";
        default:
            throw new MatchError(BoxesRunTime.boxToInteger(x));
    }
}

public String matchIntUnion(final int x) {
    if (1 == x) {
        return "one";
    } else if (2 == x) {
        return "two";
    } else if (3 == x) {
        return "three";
    } else if (4 == x) {
        return "four";
    } else if (5 == x) {
        return "five";
    } else {
        throw new MatchError(BoxesRunTime.boxToInteger(x));
    }
}

public int matchString(final String s) {
    switch (s == null ? 0 : s.hashCode()) {
        case 110182:
            if ("one".equals(s)) {
                return 1;
            }
            break;
        case 115276:
            if ("two".equals(s)) {
                return 2;
            }
            break;
        case 3143346:
            if ("five".equals(s)) {
                return 5;
            }
            break;
        case 3149094:
            if ("four".equals(s)) {
                return 4;
            }
            break;
        case 110339486:
            if ("three".equals(s)) {
                return 3;
            }
    }

    throw new MatchError(s);
}

public int matchStringUnion(final String s) {
    if ("one".equals(s)) {
        return 1;
    } else if ("two".equals(s)) {
        return 2;
    } else if ("three".equals(s)) {
        return 3;
    } else if ("four".equals(s)) {
        return 4;
    } else if ("five".equals(s)) {
        return 5;
    } else {
        throw new MatchError(s);
    }
}

Expectation

Emit a switch instruction when all members of the union share a base type with a switch-compatible type. For example:

  • matching on 1 | 2 | 3 | 4 | 5 can emit a switch because the union widens to Int
  • matching on "one" | "two" | "three" | "four" | "five" can emit a switch because the union widens to String
  • matching on 'a' | 'b' | 'c' can emit a switch because the union widens to Char
  • matching on 1 | 2 | 3 | "four" | "five" cannot emit a switch

Byte or Short can also be used in a switch but there's no syntax to make literals for those types.

Metadata

Metadata

Assignees

No one assigned

    Labels

    itype:bugstat:needs triageEvery issue needs to have an "area" and "itype" label

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions